# youcam-cli

`youcam` is the command-line interface for the [YouCam AI APIs](https://yce.perfectcorp.com/ai-api). Every one of its AI features (face and body editing, hair, skin analysis, makeup, virtual try-on, background and photo editing, image and video generation...etc.) runs from the terminal with the same models and parameters as the API. You can also check task status, browse predefined templates, and look up your units and feature costs.

The CLI works whether you are evaluating a feature, building an integration, or automating a pipeline:

- **Evaluating YouCam API AI features**: run a feature on your own photos and check the results, e.g. to compare styles or confirm a feature fits your product. No code needed.
- **Integrating the API**: try any endpoint from the terminal before writing code. Options map one-to-one to request fields, and each feature links to its [API reference](#available-ai-features).
- **AI agents**: Claude Code, Cursor, Codex and other agents can use any YouCam feature as a plain shell command. Every command prints JSON and exits with code 1 on failure, every feature and option is self-described in `--help`, and invalid values are rejected before a request is sent.
- **Automation and batch jobs**: run features from shell scripts, CI pipelines, or containers over whole folders of product shots and portraits. Local files are uploaded for you, with no upload step to script.


## Requirements

- **[Node.js](https://nodejs.org/) 18 or later** (and npm).
- A [YouCam API key](https://yce.perfectcorp.com/api-console/en/api-keys/).


## Installation

```bash
npm install -g @youcam_cli/youcam-cli

# Verify the installation
youcam --help

# Version of the YouCam CLI
youcam --version
```

To uninstall, run `npm uninstall -g @youcam_cli/youcam-cli`.

## Authentication

`youcam auth login <apiKey>` saves your API key once, the key is stored locally and reused by every later command.

```bash
youcam auth login <apiKey>

# or explicitly with a flag
youcam auth login --api-key <apiKey>

# Remove the saved API key (logout CLI tool)
youcam auth logout

# List the available authentication options
youcam auth --help
```

`auth login` writes the key to a plain JSON file, `~/.youcam-cli/credentials.json`:

```json
{
  "apiKey": "<your-api-key>"
}
```

- Every `run`, `status`, `template` and `client` command reads this file automatically.
- When `YOUCAM_CLI_API_KEY` environment variable is set, it takes precedence over the saved key.


## Quick start

Run your first AI task, from checking your units to downloading the result. This runs one real task, so it uses units (see [Checking feature cost](#checking-feature-cost)).

Every YouCam feature runs as a background task: you start it, get a `task_id` back, then check that `task_id` until the result is ready.

**1. Install and log in** (see [Installation](#installation) and [Authentication](#authentication) for details)

```bash
npm install -g @youcam_cli/youcam-cli
youcam auth login <apiKey>
```

**2. Check your units**

```bash
youcam client credit
```

Response:

```json
{
  "status": 200,
  "results": [
 {
 "id": 0,
 "type": "ApiPaygToken",
 "amount": 8193,
 "amount_dec": 8193,
 "expiry": 1801958399000
 }
  ]
}
```

`amount` is the number of units in each entry, and `expiry` is when they expire (milliseconds since the Unix epoch). The command is named `credit` because the API calls a unit a "credit" (see [Units and feature cost](#units-and-feature-cost)).

**3. Start a task**

This enhances a sample photo to twice its resolution with [AI Photo Enhance](https://docs.perfectcorp.com/reference/ai_photo_enhance/v1.0/paths/~1s2s~1v2.0~1task~1enhance/post):

```bash
youcam run enhance --src_file "https://plugins-media.makeupar.com/strapi/assets/hair_color_03_81c0c8a3c8.jpg" --scale 2
```

Response:

```json
{
  "status": 200,
  "data": {
 "task_id": "32tu4jQvRbI9NfnKlw13cls8tyT1zA2ZoOtKq-RkiTL_FrIEOLYHJX1HxYVrnWz"
  }
}
```

The CLI also prints the command for the next step. It goes to stderr, so stdout stays pure JSON for scripts:

```
Run `youcam status enhance 32tu4jQvRbI9NfnKlw13cls8tyT1zA2ZoOtKq-RkiTL_FrIEOLYHJX1HxYVrnWz` to check the result.
```

To use your own photo, pass a local path instead, e.g. `--src_file ./photo.jpg`.

**4. Check & download the result**

```bash
youcam status enhance <task_id>
```

While the task is still processing, `task_status` is `running`; run the command again after a few seconds. Once it is done:

```json
{
  "status": 200,
  "data": {
 "error": null,
 "results": {
 "url": "https://yce-us.s3-accelerate.amazonaws.com/ttl30/.../509f8acd-8d41-4459-aa31-1d4738d7a922.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...&X-Amz-Expires=7200&..."
 },
 "task_status": "success"
  }
}
```

`results.url` is the enhanced image. It is a signed link that expires after 2 hours (`X-Amz-Expires=7200`), so download it soon.

**Next steps**

- Browse the [available AI features](#available-ai-features), and run `youcam run <feature> --help` to see a feature's options.
- Learn how options, files and JSON parameters work in [Running an AI task](#running-an-ai-task).
- Some features detect faces or bodies first, see [Pre-process](#pre-process-face-and-body-detection).


## Units and feature cost

Units are what you spend to use the YouCam API, and each AI feature uses a different number of them. The API, and therefore the CLI, calls a unit a "credit", which is why the commands are `client credit` and `client credit-history`. See [What does 'Unit' mean, and how is it used?](https://docs.perfectcorp.com/develop/faq) in the official FAQ.

### Checking your units

```bash
youcam client credit  # remaining units
youcam client credit-history  # unit usage history
```

### Checking feature cost

Look up how many units a feature consumes before running it at scale.

```bash
youcam client feature-cost
```

Both commands page their results with `--page_size` and `--starting_token <token>`:

- `credit-history`: `--page_size <1-30>`, default 20.
- `feature-cost`: `--page_size <1-20>`, default 20.


> Note: [Pre-process](#pre-process-face-and-body-detection) detection tasks and [listing predefined templates](#listing-predefined-templates) do not consume units.


## Command overview

```
youcam <command> [options]

Commands:
  auth Manage authentication credentials
  run  Run an AI task
  status  Check the status of an AI task
  template   List predefined templates
  client  Get account/credit info
  help Display help for a command
```

Every command and sub-command supports `-h, --help` to show its own usage and options:

```bash
youcam run --help
youcam run face-swap --help
```

Results are printed as JSON. A command exits with code 1 when the request fails.

## API ↔ CLI command mapping

Every endpoint in the [API reference](https://docs.perfectcorp.com/) maps predictably to a CLI command:

| REST endpoint | CLI command |
|  --- | --- |
| `POST /s2s/v{ver}/task/{feature}` | `youcam run <feature> [options]` |
| `GET /s2s/v{ver}/task/{feature}/{task_id}` | `youcam status <feature> <task_id>` |
| `POST /s2s/v{ver}/task/{feature}/pre-process` | `youcam run pre-process <feature> [options]` |
| `GET /s2s/v{ver}/task/{feature}/pre-process/{task_id}` | `youcam status pre-process <feature> <task_id>` |
| `GET /s2s/v{ver}/task/template/{feature}` | `youcam template <feature> [--page_size] [--starting_token]` |
| Public makeup-vto pattern catalogs | `youcam template makeup-vto <categories...>` |
| `GET /s2s/v1.0/client/credit` | `youcam client credit` |
| `GET /s2s/v1.0/client/credit/history` | `youcam client credit-history [--page_size] [--starting_token]` |
| `GET /s2s/v2.0/credit/feature-cost` | `youcam client feature-cost [--page_size] [--starting_token]` |
| `POST /s2s/v2.0/file` + presigned `PUT` upload | Done automatically when a file option is a local path (see [Uploading files](#uploading-files)) |


Rules of thumb for deriving `<feature>` from the API reference:

- The CLI feature name is the path segment right before `{task_id}`, e.g. `/s2s/v2.0/task/abs-shape/{task_id}` → `abs-shape`.
- The API version prefix (`v2.0`, `v2.1`, …) is handled for you: each command calls the latest API version in the [API reference](https://docs.perfectcorp.com/), e.g. `skin-analysis` and `hair-transfer` call `/s2s/v2.1/...`. When a feature has several engine versions, only the newest is offered, e.g. `cloth-v4` but not `cloth-v3`.
- A few endpoints have an extra path segment, drop it to get the CLI name:
| API path | CLI command |
|  --- | --- |
| `/s2s/v2.0/task/2d-vto/earring` (same for `necklace`, `ring`, `bracelet`, `watch`) | `youcam run earring` |
| `/s2s/v2.0/task/image-to-image/youcam`, `/text-to-image/youcam`, `/image-to-video/youcam`, `/text-to-video/youcam` | `youcam run image-to-image`, `run text-to-image`, `run image-to-video`, `run text-to-video` |
| `/s2s/v2.0/task/colorize/color-correct` | `youcam run color-correct` |
- Request body properties become `--<property_name>` options on the matching `run` command (see [Uploading files](#uploading-files) and [Passing JSON parameters](#passing-json-parameters)). Query parameters such as `page_size` and `starting_token` become `--<param_name>` options too.


Take [AI Hair Color Virtual Try-On](https://docs.perfectcorp.com/reference/ai_hair_color/v1.0/paths/~1s2s~1v2.0~1task~1hair-color/post) as an example, its two endpoints are:

```
POST /s2s/v2.0/task/hair-color   { src_file_url | src_file_id, preset?, pattern?, palettes? }
GET  /s2s/v2.0/task/hair-color/{task_id}
```

map to these CLI commands:

```bash
youcam run hair-color --src_file <url-or-path> [--preset <value> | --pattern <json> --palettes <json>]
youcam status hair-color <task_id>
```

To apply a preset color:

```bash
youcam run hair-color --src_file "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg" --preset "Honey Blonde"
youcam status hair-color <task_id>
```

The `run` command sends this request body:

```json
{
  "src_file_url": "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg",
  "preset": "Honey Blonde"
}
```

To apply a custom color instead, pass the `pattern` and `palettes` objects:

```bash
youcam run hair-color --src_file "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg" \
  --pattern '{"name": "full"}' \
  --palettes '[{"color": "#8B4513", "color_intensity": 80, "shine_intensity": 50}]'
youcam status hair-color <task_id>
```

The equivalent JSON request body is:

```json
{
  "src_file_url": "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg",
  "pattern": { "name": "full" },
  "palettes": [{ "color": "#8B4513", "color_intensity": 80, "shine_intensity": 50 }]
}
```

`youcam run` prints the new `task_id`; pass it to `youcam status` and repeat until `task_status` is `success`.

## Running an AI task

Each AI feature is a sub-command of `run`. Options vary per feature; use `--help` on the feature to see its inputs.

```bash
youcam run <feature> [options]
```

For instance, to run [AI Abs Filter](https://docs.perfectcorp.com/reference/ai_abs_filter/v1.0/paths/~1s2s~1v2.0~1task~1abs-shape/post):

```bash
youcam run abs-shape --src_file "https://example.com/photo.jpg" --mode "Six-pack" --intensity 2
```

Running a task returns a `task_id`, which you use to [check its status](#checking-task-status).

- **Pre-process:** a few features detect the faces or bodies in the photo first, so you can choose which person to process. See [Pre-process](#pre-process-face-and-body-detection).
- **Templates:** some features accept a ready-made style preset through `--template_id`. See [Listing predefined templates](#listing-predefined-templates).
- **Validation:** option values are checked against the API schema before anything is sent. Options with a fixed set of values list them in `--help`, and an invalid value is rejected with the allowed choices.


## Uploading files

Every feature that takes an image or video exposes it as a single `--src_file` option, even though the API accepts two mutually exclusive fields: `src_file_url` (a public URL) or `src_file_id` (the ID of an uploaded file). The CLI picks the right one based on what you pass:

- **A publicly accessible URL** is sent as `src_file_url`. Nothing is uploaded.

```bash
youcam run enhance --src_file "https://example.com/photo.jpg" --scale 2
```
- **A local file path** is uploaded for you, and the task is sent with `src_file_id`:
  1. `POST /s2s/v2.0/file` registers the file (name, content type, size) and returns a presigned upload URL and a `file_id`.
  2. The file's bytes are `PUT` to that presigned URL.
  3. `run <feature>` is called with `src_file_id` set to that `file_id`.

```bash
youcam run enhance --src_file ./photo.jpg --scale 2
```
Windows paths work too in PowerShell or cmd:

```powershell
youcam run enhance --src_file .\photo.jpg --scale 2
```


Notes:

- Local files must be `.jpg`, `.jpeg`, `.png` or `.mp4`.
- Size, resolution and duration limits depend on the feature, an oversized file makes the task fail with `exceed_max_filesize` in `status`.
- There is no separate upload CLI command, uploads happen only through file options.


### Other file options

Beyond `--src_file`, some features take extra images (masks, reference photos, product shots). They follow the same rule: pass a public URL or a local path, and local paths are uploaded for you.

| Option | What it is | Values | Used by |
|  --- | --- | --- | --- |
| `--src_file <input>` | The main source photo or video | single | most features |
| `--src_files <inputs...>` | Several source photos | multiple | `hair-frizziness-detection`, `hair-type-detection`, `image-to-image` |
| `--ref_file <input>` | A reference image to copy from (e.g. a makeup look, an outfit, a product) | single | `bag`, `cloth-v4`, `eye-color-vto`, `hair-transfer`, `hat`, `mu-transfer`, `ai-nail`, `scarf`, `shoes-transfer`, `bg-replace-vid`, `face-swap-vid` |
| `--ref_files <inputs...>` | Several reference images (e.g. one face per target, product shots) | multiple | `bracelet`, `earring`, `face-swap`, `nail-vto`, `necklace`, `ring`, `watch` |
| `--msk_file <input>` | Mask over the source: white marks the area to change, black is left as is | single | `generative-fill`, `obj-replace`, `obj-rem-vid` |
| `--srcmsk_file <input>` | Mask isolating the relevant body part in the source (e.g. ears, neck, wrist) | single | `bracelet`, `earring`, `necklace`, `ring`, `watch` |
| `--refmsk_files <inputs...>` | Masks matching each `--ref_files` entry, in the same order | multiple | `bracelet`, `earring`, `ring`, `watch` |


Options with `...` take several values after one flag, separated by spaces (not commas):

```bash
youcam run face-swap \
  --src_file group-photo.jpg \
  --ref_files person-a.jpg person-b.jpg \
  --face_mapping '[{"index":0,"position":0},{"index":1,"position":1}]'
```

If one multi-value option mixes public URLs and local paths, e.g. `--ref_files https://example.com/a.jpg ./b.jpg`, every file in it is uploaded, the URLs included: the CLI downloads each URL, uploads it like a local file, and sends all of them as file IDs (e.g. `ref_file_ids`). Those URLs must then serve a JPG, PNG or MP4. To have URLs sent as URLs, pass only URLs in that option.

Run `youcam run <feature> --help` to see exactly which of these a feature accepts.

## Option syntax

These forms listed below are equivalent, use whichever you prefer:

```bash
youcam run skin-simulation --src_file https://example.com/face.png --acne 1
youcam run skin-simulation --src_file=https://example.com/face.png --acne=1
youcam run skin-simulation --src_file="https://example.com/face.png" --acne="1"
```

- Quotes are only needed when a value contains spaces or characters your shell treats specially (e.g. `&` in a URL, or JSON).
- Options that take several values accept them space-separated after one flag, or as a repeated flag:
  - `--src_files a.jpg b.jpg`
  - `--src_files=a.jpg --src_files=b.jpg`
  - Not `--src_files=a.jpg b.jpg`, which is rejected.


## Passing JSON parameters

Options shown as `<json>` in `--help` (instead of `<value>`) correspond to an `object` or `array` field in the API request body. Pass the whole structure as one JSON value:

- inline JSON, e.g. `--pattern '{"name":"full"}'`
- a path to a `.json` file, e.g. `--effects ./effects.json`
- `-` to read the JSON from stdin, e.g. `cat effects.json | youcam run makeup-vto --src_file photo.jpg --effects -`


**Quoting inline JSON:**

```bash
# bash / zsh / macOS / Linux / Git Bash: single quotes protect the double quotes
youcam run hair-color --src_file photo.jpg --pattern '{"name":"full"}' --palettes '[{"color":"#8B4513","color_intensity":80,"shine_intensity":50}]'

# Windows PowerShell: escape the inner double quotes
youcam run hair-color --src_file photo.jpg --pattern '{\"name\":\"full\"}' --palettes '[{\"color\":\"#8B4513\",\"color_intensity\":80,\"shine_intensity\":50}]'
```

**Nested object and array:** `hair-color`'s `--pattern` is an `object`, and `--palettes` an `array` of `{color, color_intensity, shine_intensity}` objects (one for full mode, two for ombre mode):

```bash
youcam run hair-color \
  --src_file photo.jpg \
  --pattern '{"name":"full"}' \
  --palettes '[{"color":"#FF5733","color_intensity":80,"shine_intensity":50}]'
```

Once `photo.jpg` is uploaded and resolved to a `src_file_id`, the CLI sends this body to `POST /s2s/v2.0/task/hair-color`:

```json
{
  "src_file_id": "<file_id from the upload>",
  "pattern": {
 "name": "full"
  },
  "palettes": [
 {
 "color": "#FF5733",
 "color_intensity": 80,
 "shine_intensity": 50
 }
  ]
}
```

Each `--<option> <json>` value is used as that property's value as-is: `--pattern` becomes the `pattern` object and `--palettes` the `palettes` array. Nothing is renamed or reshaped, and no defaults are added for options you leave out.

**Deeply nested arrays:** `makeup-vto`'s `--effects` is an array of effect objects, some with their own `pattern` and `palettes`. Multi-line JSON is fine:

```bash
youcam run makeup-vto --src_file photo.jpg --effects '[
  {"category":"skin_smooth","skinSmoothStrength":55,"skinSmoothColorIntensity":45},
  {"category":"blush","pattern":{"name":"1color1"},"palettes":[
 {"color":"#e19f9f","texture":"matte","colorIntensity":60}
  ]}
]'
```

Pattern names such as `1color1` come from `youcam template makeup-vto` (see [Listing makeup-vto pattern names](#listing-makeup-vto-pattern-names)).

Invalid JSON, or a value of the wrong type, is rejected before the request is sent and names the offending field, e.g. `Invalid value for --palettes: [{"color":123}] (0.color: Invalid input: expected string, received number)`.

## Checking task status

```bash
youcam status <feature> <task_id>
# or
youcam status <feature> --task_id <task_id>
```

Example:

```bash
youcam status abs-shape 1234567890abcdef
```

Poll until `task_status` is `success` (or `error`); the response then includes the results, such as output file URLs. For a pre-process task, use `youcam status pre-process <feature> <task_id>`.

## Pre-process (face and body detection)

> Pre-process tasks use no units, only the main task does.


For the features below, a photo can contain several people, so you choose which one to process. `youcam run pre-process <feature>` detects the faces or bodies in the photo and returns them as a list. Each one is numbered by its position in that list: `0` for the first, `1` for the second, and so on.

1. Detect: `youcam run pre-process <feature> --src_file <photo>` returns a `task_id`.
2. Read the detections: `youcam status pre-process <feature> <task_id>` lists the detected faces or bodies. The list's form depends on the feature: `body-reshape` returns `results.result[]`, boxes relative to the image size (`0`–`1`), while `face-swap` returns `results.faces[].bbox`, pixel boxes as `[x1, y1, x2, y2]` (top-left and bottom-right corners).
3. Run the feature on the same photo, passing the chosen number with the option in this table:


| Feature | Option that takes the detected face or body number |
|  --- | --- |
| `body-reshape` | `--index <number>` |
| `face-lift` | `--index <number>` |
| `face-reshape` | `--index <number>` |
| `fitzpatrick-scale-analyzer` | `--index <number>` |
| `teeth-whiten` | `--index <number>` |
| `face-swap` | `"position"` in each `--face_mapping` entry. That entry's `"index"` picks which `--ref_files` image to use |


For example, `youcam run face-lift --src_file <photo> --index 1 ...` lifts the second detected face. See the [example workflow](#example-workflow) for a full run with real output.

## Listing predefined templates

Some features ship with ready-to-use templates (style or look presets) that you reference with `--template_id` instead of building parameters yourself.

```bash
youcam template <feature> [--page_size <1-20>] [--starting_token <token>]
```

`<feature>` is one of:

| Category | Features |
|  --- | --- |
| Hair & beard | `hair-bang`, `hair-curl`, `hair-ext`, `hair-transfer`, `hair-vol`, `beard-style` |
| Makeup & try-on | `look-vto`, `fabric` |
| Image | `ai-avatar`, `ai-studio`, `headshot`, `bg-replace` |
| Video | `video-trans` |


For `makeup-vto`, see [Listing makeup-vto pattern names](#listing-makeup-vto-pattern-names) for the details of its patterns.

Example:

```bash
youcam template ai-avatar --page_size 10
youcam run ai-avatar --src_file ./photo.jpg --template_id <id> --output_count 1
```

Pass the `next_token` from a response as `--starting_token` to fetch the next page.

When the `ai-avatar` task succeeds, `youcam status ai-avatar <task_id>` lists the generated images in `results.output[].url`, one entry per output.

### Listing makeup-vto pattern names

`makeup-vto` effects pick their shape by name, e.g. `"pattern":{"name":"1color1"}` for blush or `"shape":{"name":"plump"}` for lip color. List the valid names for each effect category:

```bash
youcam template makeup-vto <categories...>
```

Pass one or more of `blush`, `bronzer`, `contour`, `eyebrows`, `eyeliner`, `eyeshadow`, `eyelashes`, `lipshape`, `lipliner`, `highlighter` (or the same names after `--category`). At least one is required. The catalogs are public, so listing them uses no units.

```bash
youcam template makeup-vto blush lipshape
```

The result is keyed by category. Use an entry's `label` as the pattern name; `colorNum` (blush, eyeliner and eyeshadow only) is how many `palettes` that pattern needs:

```json
{
  "blush": [
 {
 "category": "1 color",
 "label": "1color1",
 "thumbnail": "https://app-cdn-01.makeupar.com/.../a53cd4f4-43b6-4e19-b85a-ec7a95c6a47f.jpg",
 "tags": [
  { "id": 100, "name": "Blush 3D" },
  { "id": 103, "name": "Oblong" }
 ],
 "colorNum": 1
 }
  ],
  "lipshape": [
 {
 "category": "general",
 "label": "original",
 "thumbnail": "https://plugins-media.makeupar.com/wcm-saas/images/lipshapes/original.png",
 "tags": []
 }
  ]
}
```

A category that can't be fetched shows `{ "error": "..." }` instead, and the command exits with code 1.

## Available AI features

Pass any of these as `<feature>` to `run` and `status`. Each links to its API reference page. For the features that have a detection step, see [Pre-process](#pre-process-face-and-body-detection). For the ones that work with `youcam template`, see [Listing predefined templates](#listing-predefined-templates).

### Beauty

- [makeup-vto](https://docs.perfectcorp.com/reference/makeup_vto/v1.0/paths/~1s2s~1v2.0~1task~1makeup-vto/post)
  - [pattern names](#listing-makeup-vto-pattern-names)
- [mu-transfer](https://docs.perfectcorp.com/reference/ai_makeup_transfer/v1.0/paths/~1s2s~1v2.0~1task~1mu-transfer/post)
- [look-vto](https://docs.perfectcorp.com/reference/ai_look_vto/v1.0/paths/~1s2s~1v2.0~1task~1look-vto/post)
- [eye-color-vto](https://docs.perfectcorp.com/reference/ai_eye_color_lens/v1.0/paths/~1s2s~1v2.0~1task~1eye-color-vto/post)
- [nail-vto](https://docs.perfectcorp.com/reference/ai_nail_vto/v1.0/paths/~1s2s~1v2.0~1task~1nail-vto/post)
- [ai-nail](https://docs.perfectcorp.com/reference/ai_nail_transfer/v1.0/paths/~1s2s~1v2.0~1task~1ai-nail/post)


### Skin, face & body

- [face-attr-analysis](https://docs.perfectcorp.com/reference/ai_face_analyzer/v1.0/paths/~1s2s~1v2.0~1task~1face-attr-analysis/post)
- [skin-analysis](https://docs.perfectcorp.com/reference/ai_skin_analysis/v2.1/paths/~1s2s~1v2.1~1task~1skin-analysis/post)
- [skin-tone-analysis](https://docs.perfectcorp.com/reference/ai_skin_tone_analysis/v1.0/paths/~1s2s~1v2.0~1task~1skin-tone-analysis/post)
- [fitzpatrick-scale-analyzer](https://docs.perfectcorp.com/reference/ai_fitzpatrick_skin_type/v1.0/paths/~1s2s~1v2.0~1task~1fitzpatrick-scale-analyzer/post)
- [skin-simulation](https://docs.perfectcorp.com/reference/ai_skin_simulation/v1.0/paths/~1s2s~1v2.0~1task~1skin-simulation/post)
- [abs-shape](https://docs.perfectcorp.com/reference/ai_abs_filter/v1.0/paths/~1s2s~1v2.0~1task~1abs-shape/post)
- [aging](https://docs.perfectcorp.com/reference/ai_aging_simulation/v1.0/paths/~1s2s~1v2.0~1task~1aging/post)
- [body-reshape](https://docs.perfectcorp.com/reference/ai_body_reshape/v1.0/paths/~1s2s~1v2.0~1task~1body-reshape/post)
- [breast-shape](https://docs.perfectcorp.com/reference/ai_breast_augmentation/v1.0/paths/~1s2s~1v2.0~1task~1breast-shape/post)
- [face-lift](https://docs.perfectcorp.com/reference/ai_face_lift/v1.0/paths/~1s2s~1v2.0~1task~1face-lift/post)
- [face-reshape](https://docs.perfectcorp.com/reference/ai_face_reshape/v1.0/paths/~1s2s~1v2.0~1task~1face-reshape/post)
- [ai-smile](https://docs.perfectcorp.com/reference/ai_smile/v1.0/paths/~1s2s~1v2.0~1task~1ai-smile/post)
- [teeth-whiten](https://docs.perfectcorp.com/reference/ai_teeth_whitening/v1.0/paths/~1s2s~1v2.0~1task~1teeth-whiten/post)


### Hair & beard

- [hair-density-detection](https://docs.perfectcorp.com/reference/ai_hair_density_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-density-detection/post)
- [hair-frizziness-detection](https://docs.perfectcorp.com/reference/ai_hair_frizziness_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-frizziness-detection/post)
- [hair-length-detection](https://docs.perfectcorp.com/reference/ai_hair_length_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-length-detection/post)
- [hair-type-detection](https://docs.perfectcorp.com/reference/ai_hair_type_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-type-detection/post)
- [hair-bang](https://docs.perfectcorp.com/reference/ai_bangs/v1.0/paths/~1s2s~1v2.0~1task~1hair-bang/post)
- [hair-color](https://docs.perfectcorp.com/reference/ai_hair_color/v1.0/paths/~1s2s~1v2.0~1task~1hair-color/post)
- [hair-curl](https://docs.perfectcorp.com/reference/ai_wavy_hair/v1.0/paths/~1s2s~1v2.0~1task~1hair-curl/post)
- [hair-ext](https://docs.perfectcorp.com/reference/ai_hair_extension/v1.0/paths/~1s2s~1v2.0~1task~1hair-ext/post)
- [hair-transfer](https://docs.perfectcorp.com/reference/ai_hairstyle/v2.1/paths/~1s2s~1v2.1~1task~1hair-transfer/post)
- [hair-vol](https://docs.perfectcorp.com/reference/ai_hair_volume/v1.0/paths/~1s2s~1v2.0~1task~1hair-vol/post)
- [beard-style](https://docs.perfectcorp.com/reference/ai_beard_style/v1.0/paths/~1s2s~1v2.0~1task~1beard-style/post)


### Virtual try-on

- [earring](https://docs.perfectcorp.com/reference/ai_earrings/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1earring/post)
- [necklace](https://docs.perfectcorp.com/reference/ai_necklace/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1necklace/post)
- [ring](https://docs.perfectcorp.com/reference/ring_vto/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1ring/post)
- [bracelet](https://docs.perfectcorp.com/reference/ai_bracelet/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1bracelet/post)
- [watch](https://docs.perfectcorp.com/reference/ai_watch/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1watch/post)
- [bag](https://docs.perfectcorp.com/reference/ai_bag/v2.0/paths/~1s2s~1v2.0~1task~1bag/post)
- [hat](https://docs.perfectcorp.com/reference/ai_hat/v2.0/paths/~1s2s~1v2.0~1task~1hat/post)
- [scarf](https://docs.perfectcorp.com/reference/ai_scarf/v2.0/paths/~1s2s~1v2.0~1task~1scarf/post)
- [cloth-v4](https://docs.perfectcorp.com/reference/ai_clothes/v4.0/paths/~1s2s~1v2.0~1task~1cloth-v4/post)
- [fabric](https://docs.perfectcorp.com/reference/ai_fabric/v1.0/paths/~1s2s~1v2.0~1task~1fabric/post)
- [shoes-transfer](https://docs.perfectcorp.com/reference/ai_shoes/v3.0/paths/~1s2s~1v2.0~1task~1shoes-transfer/post)


### Image

- [enhance](https://docs.perfectcorp.com/reference/ai_photo_enhance/v1.0/paths/~1s2s~1v2.0~1task~1enhance/post)
- [lighting](https://docs.perfectcorp.com/reference/ai_photo_lighting/v2.0/paths/~1s2s~1v2.0~1task~1lighting/post)
- [colorize](https://docs.perfectcorp.com/reference/ai_photo_colorize/v1.0/paths/~1s2s~1v2.0~1task~1colorize/post)
- [color-correct](https://docs.perfectcorp.com/reference/ai_color_correction/v1.0/paths/~1s2s~1v2.0~1task~1colorize~1color-correct/post)
- [sod](https://docs.perfectcorp.com/reference/ai_background_removal/v1.0/paths/~1s2s~1v2.0~1task~1sod/post)
- [bg-blur](https://docs.perfectcorp.com/reference/ai_photo_background_blur/v2.0/paths/~1s2s~1v2.0~1task~1bg-blur/post)
- [bg-replace](https://docs.perfectcorp.com/reference/ai_photo_background_change/v2.0/paths/~1s2s~1v2.0~1task~1bg-replace/post)
- [generative-fill](https://docs.perfectcorp.com/reference/ai_object_removal_pro/v4.0/paths/~1s2s~1v2.0~1task~1generative-fill/post)
- [obj-replace](https://docs.perfectcorp.com/reference/ai_replace/v1.0/paths/~1s2s~1v2.0~1task~1obj-replace/post)
- [out-paint](https://docs.perfectcorp.com/reference/ai_image_extender/v2.0/paths/~1s2s~1v2.0~1task~1out-paint/post)
- [image-to-image](https://docs.perfectcorp.com/reference/ai_image_generator/v2.0/paths/~1s2s~1v2.0~1task~1image-to-image~1youcam/post)
- [text-to-image](https://docs.perfectcorp.com/reference/ai_image_generator/v2.0/paths/~1s2s~1v2.0~1task~1text-to-image~1youcam/post)
- [ai-avatar](https://docs.perfectcorp.com/reference/ai_avatar_generator/v3.0/paths/~1s2s~1v2.0~1task~1ai-avatar/post)
- [ai-studio](https://docs.perfectcorp.com/reference/ai_studio_generator/v3.0/paths/~1s2s~1v2.0~1task~1ai-studio/post)
- [headshot](https://docs.perfectcorp.com/reference/ai_headshot_generator/v1.0/paths/~1s2s~1v2.0~1task~1headshot/post)
- [wmk-removal](https://docs.perfectcorp.com/reference/ai_watermark_removal/v1.0/paths/~1s2s~1v2.0~1task~1wmk-removal/post)
- [face-swap](https://docs.perfectcorp.com/reference/ai_face_swap/v1.0/paths/~1s2s~1v2.0~1task~1face-swap/post)


### Video

- [bg-replace-vid](https://docs.perfectcorp.com/reference/ai_video_background_replace/v1.0/paths/~1s2s~1v2.0~1task~1bg-replace-vid/post)
- [face-swap-vid](https://docs.perfectcorp.com/reference/ai_video_face_swap/v1.0/paths/~1s2s~1v2.0~1task~1face-swap-vid/post)
- [image-to-video](https://docs.perfectcorp.com/reference/ai_video_generator/v2.0/paths/~1s2s~1v2.0~1task~1image-to-video~1youcam/post)
- [text-to-video](https://docs.perfectcorp.com/reference/ai_video_generator/v2.0/paths/~1s2s~1v2.0~1task~1text-to-video~1youcam/post)
- [obj-rem-vid](https://docs.perfectcorp.com/reference/ai_video_object_removal/v2.1/paths/~1s2s~1v2.0~1task~1obj-rem-vid/post)
- [video-sr](https://docs.perfectcorp.com/reference/ai_video_enhancer/v1.0/paths/~1s2s~1v2.0~1task~1video-sr/post)
- [video-trans](https://docs.perfectcorp.com/reference/ai_video_style_transfer/v1.0/paths/~1s2s~1v2.0~1task~1video-trans/post)


Run `youcam run <feature> --help` for the exact parameters each feature accepts.

## Example workflow

This walks through [AI Body Reshape](https://docs.perfectcorp.com/reference/ai_body_reshape/v1.0/paths/~1s2s~1v2.0~1task~1body-reshape/post) from start to finish — detect the bodies in a photo, pick one, reshape it, and fetch the result. The request and response bodies below were captured from real runs with this sample photo:

**1. Start the detection (pre-process) task**

```bash
youcam run pre-process body-reshape \
  --src_file "https://plugins-media.makeupar.com/strapi/assets/body_reshape_01_d10c50c97d.jpg"
```

Response:

```json
{
  "status": 200,
  "data": {
 "task_id": "CKPWaMO-olxd1ECr_3tTDXW5Gu_tQw0EKgN0-dU27zSyXhV8cJR2TzYLMhDqD"
  }
}
```

**2. Get the detected bodies**

```bash
youcam status pre-process body-reshape CKPWaMO-olxd1ECr_3tTDXW5Gu_tQw0EKgN0-dU27zSyXhV8cJR2TzYLMhDqD
```

Response:

```json
{
  "status": 200,
  "data": {
 "error": null,
 "results": {
 "result": [
  {
  "left": 0.35347824096679686,
  "top": 0.022326231002807617,
  "width": 0.3041056156158447,
  "height": 0.951037073135376
  }
 ],
 "timed": 4565
 },
 "task_status": "success"
  }
}
```

Each entry in `results.result` is one detected person, as a bounding box relative to the image size (`0`–`1`). Its position in the array is the `--index` to pass next; this photo has one person, so the index is `0`.

**3. Run the main task on the chosen person**

```bash
youcam run body-reshape \
  --src_file "https://plugins-media.makeupar.com/strapi/assets/body_reshape_01_d10c50c97d.jpg" \
  --version 1.0 \
  --index 0 \
  --features '{"slim": 20}'
```

Response:

```json
{
  "status": 200,
  "data": {
 "task_id": "ZV3WIzcB1rk7I5o8hMxKP5VdgIEpnHf7VOpsk1YC76tZy2Wur0lg4Bunb3KY-7Qa"
  }
}
```

**4. Poll the main task until it finishes**

```bash
youcam status body-reshape ZV3WIzcB1rk7I5o8hMxKP5VdgIEpnHf7VOpsk1YC76tZy2Wur0lg4Bunb3KY-7Qa
```

While the task runs, `task_status` is `running`; repeat the command every few seconds. Once it succeeds (`GET /s2s/v2.0/task/body-reshape/{task_id}`):

```json
{
  "status": 200,
  "data": {
 "error": null,
 "results": {
 "url": "https://yce-us.s3-accelerate.amazonaws.com/ttl30/.../0b333891-60be-4cd1-81cd-7d8cae35b3eb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...&X-Amz-Expires=7200&...",
 "timed": 12131,
 "slim": true
 },
 "task_status": "success"
  }
}
```

`results.url` is the reshaped image. It is a signed link that expires (`X-Amz-Expires=7200`, i.e. 2 hours), so download it soon after the task succeeds.

## Debugging guide

The CLI sends standard YouCam API requests, so everything in the API documentation applies unchanged: the same [rate limits](https://docs.perfectcorp.com/develop/rate_limit), [error codes](https://docs.perfectcorp.com/develop/error_codes), and [file retention periods](https://docs.perfectcorp.com/develop/file_retention_period). See also the API's own [Debugging Guide](https://docs.perfectcorp.com/develop/debugging_guide).

### Where an error shows up

A problem can surface at three points:

| Where it fails | Exit code | stdout | stderr | See |
|  --- | --- | --- | --- | --- |
| The CLI rejects the command before sending it | `1` | empty | error message | [CLI errors](#cli-errors) |
| The API rejects the request | `1` | JSON with `status`, `error` and `error_code` | empty | [API request errors](#api-request-errors) |
| The task runs but fails | `0` | JSON with `"task_status": "error"`, a code in `data.error` and a description in `data.error_message` | empty | [Task errors](#task-errors) |


A failed task still exits with `0`, because the `status` request itself succeeded. Scripts must check `data.task_status`, not only the exit code.

### Rate limits

The [API rate limits](https://docs.perfectcorp.com/develop/rate_limit) apply to every `youcam` command:

- **Per IP address:** at most 250 requests per 300 seconds.
- **Per access token (API key):** at most 250 requests per 300 seconds.
- Both limits must be met. A request that breaks either one gets `429 Too Many Requests`, and the CLI exits with code `1`.
- The recommended pace is about 5 requests per second.


Most commands send one API request. `run` with local files also sends one `POST /s2s/v2.0/file` request per file before the task request. Polling counts too — checking several tasks every second can use up the limit quickly. Poll every few seconds, and when you get a `429`, wait and retry with an increasing delay instead of retrying right away.

### CLI errors

These are caught before the task request is sent, so they use no units.

| CLI Error Message | Likely cause | Solution |
|  --- | --- | --- |
| `Not authenticated. Run: youcam auth login <apiKey>, or set YOUCAM_CLI_API_KEY` | No saved API key, and `YOUCAM_CLI_API_KEY` is unset or empty | Run `youcam auth login <apiKey>`, or set `YOUCAM_CLI_API_KEY` |
| `Invalid credentials file at <path>. Re-run: youcam auth login <apiKey>` | `credentials.json` isn't valid JSON, or `apiKey` is empty or not a string | Run `youcam auth login <apiKey>`. It overwrites the file |
| `Can't log out: credentials file at <path> is invalid. Fix or delete it by hand` | `youcam auth logout` found the same invalid `credentials.json`, and left it untouched | Fix the file so it reads `{ "apiKey": "<your-api-key>" }`, then log out again, or delete the file |
| `error: required option '--scale <value>' not specified` | A required option is missing | Add it. `youcam run <feature> --help` lists every option |
| `error: option '--scale <value>' argument '9' is invalid. Allowed choices are 1, 2, 4.` | The value is not one of the allowed choices | Use one of the listed values |
| `Invalid value for --page_size: 99 (Too big: expected number to be <=20)` | The value has the wrong type or is out of range. For JSON options, the message names the field | Fix the value. See [Passing JSON parameters](#passing-json-parameters) for JSON quoting |
| `error: unknown option '--bogus'` | The option doesn't exist for this feature, or is misspelled | Check the spelling in `--help`. Options use snake_case, e.g. `--src_file`, not `--src-file` |
| `ENOENT: no such file or directory, open '...'` | The local file path is wrong | Check the path. Relative paths start from the current directory. Quote paths that contain spaces |
| `Unsupported file type "unknown" for ./notes.txt. Supported types: image/jpeg, image/png, video/mp4` | The local file is not a JPG, PNG or MP4 | Convert the file, or pass a public URL instead |
| `Missing task ID. Usage: status <feature> <task_id> (or --task_id <value>)` | `status` was run without a task ID | Pass the `task_id` that `run` printed |


### API request errors

The API rejected the request. The CLI prints the API's response on stdout, for example:

```json
{
  "status": 400,
  "error": "This task ID doesn't exist, or the task has expired.",
  "error_code": "InvalidTaskId"
}
```

| Status | `error_code` | Likely cause | Solution |
|  --- | --- | --- | --- |
| `400` | `InvalidTaskId` | The task ID is mistyped, belongs to a different feature (e.g. a `run enhance` task checked with `status hair-color`), or is older than 30 days, the period a `task_id` stays valid | Use the same feature name in `status` as in `run`. For a pre-process task, use `youcam status pre-process <feature> <task_id>`. Check tasks within 30 days of starting them |
| `401` | `InvalidAccessToken` | The saved API key is wrong or no longer active | Copy the key from the [API console](https://yce.perfectcorp.com/api-console/en/api-keys/) and run `youcam auth login` again. Don't include the `<` `>` from the usage line in the key |
| `429` | — | Too many requests from your IP address or API key | Slow down and retry with an increasing delay. See [Rate limits](#rate-limits) |


### Task errors

The task was accepted but the AI engine couldn't process it. `youcam status` returns `"task_status": "error"`, with the code in `data.error` and a description in `data.error_message`. Look the code up in the API's [Error Codes](https://docs.perfectcorp.com/develop/error_codes) page. Some features have extra codes, which are listed under "File Specs & Errors" on the feature's API reference page, along with its size, resolution and pose limits.

### Expired result links

A result URL (e.g. `results.url`, or `results.output[].url` for `ai-avatar`) works for 2 hours after the task succeeds. If it has expired, run `youcam status <feature> <task_id>` again to get a new link; this works for 30 days after the task was created. Results are deleted after 30 days, so download anything you want to keep before then.

## Getting help

```bash
youcam help
youcam help <command>
youcam <command> <subcommand> --help # e.g., youcam run pre-process --help
```