> ## Documentation Index
> Fetch the complete documentation index at: https://codebyahmed.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin Variants API — Manage Product Variants and SKUs

> Create and manage product variants with SKU, pricing, dimensions, discounts, and status. Each variant represents a purchasable unit of a product.

Every purchasable item in the catalog is represented by a variant. A variant belongs to a product and carries its own SKU, pricing, discount, physical dimensions, and lifecycle status. Use this API to build out your product's size and color matrix, set prices, manage stock readiness via status flags, and soft-delete discontinued options while retaining order history integrity.

<Note>
  All variant endpoints require an authenticated session with the `ADMIN` or `SUPER_ADMIN` role. Call `GET /auth/csrf-token` before every POST, PATCH, or DELETE request and supply the token in the `x-csrf-token` header.
</Note>

***

## Variant Status Reference

A variant's `status` field controls its visibility and purchase eligibility on the storefront.

| Status     | Description                                                         |
| ---------- | ------------------------------------------------------------------- |
| `ACTIVE`   | Visible to customers and available for purchase (subject to stock). |
| `DRAFT`    | Hidden from customers; used while the variant is being prepared.    |
| `INACTIVE` | Temporarily hidden from customers but not discontinued.             |
| `ARCHIVED` | Discontinued. Hidden from customers and not expected to return.     |

The default status when creating a variant is `DRAFT`. Transition a variant to `ACTIVE` once it is ready for sale and has an inventory record.

***

## List Variants

Retrieve a paginated list of variants for a given product. Filter by `status`, include soft-deleted entries, and sort across multiple fields.

```
GET /admin/products/{product_public_id}/variants
```

### Path Parameters

<ParamField path="product_public_id" type="string" required>
  The parent product's public ID, prefixed `prd_`.
</ParamField>

### Query Parameters

<ParamField query="page" type="integer" default="1">
  Page number (1-based).
</ParamField>

<ParamField query="limit" type="integer" default="20">
  Items per page. Accepted range: 1–100.
</ParamField>

<ParamField query="status" type="string">
  Filter by variant status. One of `ACTIVE`, `DRAFT`, `INACTIVE`, or `ARCHIVED`.
</ParamField>

<ParamField query="include_deleted" type="string" default="false">
  Pass `"true"` to include soft-deleted variants. Must be the string `"true"` or `"false"`.
</ParamField>

<ParamField query="sort" type="string" default="created_at">
  Sort field. Prefix with `-` for descending order. Accepted values: `sku`, `-sku`, `price`, `-price`, `created_at`, `-created_at`, `updated_at`, `-updated_at`.
</ParamField>

### Response

<ResponseField name="data" type="array">
  Array of variant objects.

  <Expandable title="Variant fields">
    <ResponseField name="public_id" type="string">Variant public ID, prefixed `var_`.</ResponseField>
    <ResponseField name="sku" type="string">Stock-keeping unit identifier.</ResponseField>
    <ResponseField name="barcode" type="string | null">Barcode or UPC, if set.</ResponseField>
    <ResponseField name="color" type="string | null">Color label, if set.</ResponseField>
    <ResponseField name="size" type="string | null">Size label, if set.</ResponseField>
    <ResponseField name="price" type="string">Retail price as a decimal string, e.g. `"99.99"`.</ResponseField>
    <ResponseField name="cost_price" type="string | null">Cost price as a decimal string, if set.</ResponseField>
    <ResponseField name="discount_percentage" type="string | null">Discount percentage as a decimal string (0.00–100.00), if set.</ResponseField>
    <ResponseField name="final_price" type="string">Computed selling price after discount, as a decimal string.</ResponseField>
    <ResponseField name="weight" type="string | null">Weight in your configured unit, as a decimal string.</ResponseField>
    <ResponseField name="length" type="string | null">Length dimension, as a decimal string.</ResponseField>
    <ResponseField name="width" type="string | null">Width dimension, as a decimal string.</ResponseField>
    <ResponseField name="height" type="string | null">Height dimension, as a decimal string.</ResponseField>
    <ResponseField name="status" type="string">Lifecycle status: `ACTIVE`, `DRAFT`, `INACTIVE`, or `ARCHIVED`.</ResponseField>
    <ResponseField name="deleted_at" type="string | null">ISO 8601 UTC soft-deletion timestamp, or `null`.</ResponseField>
    <ResponseField name="created_at" type="string">ISO 8601 UTC creation timestamp.</ResponseField>
    <ResponseField name="updated_at" type="string">ISO 8601 UTC last-updated timestamp.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="meta" type="object">
  <Expandable title="Pagination fields">
    <ResponseField name="total" type="integer">Total matching records.</ResponseField>
    <ResponseField name="totalPages" type="integer">Total pages.</ResponseField>
    <ResponseField name="hasNext" type="boolean">Whether a next page exists.</ResponseField>
    <ResponseField name="hasPrev" type="boolean">Whether a previous page exists.</ResponseField>
  </Expandable>
</ResponseField>

***

## Create Variant

Add a new variant to a product. `sku` and `price` are the only required fields. All other fields are optional and can be set now or updated later via PATCH.

```
POST /admin/products/{product_public_id}/variants
```

### Path Parameters

<ParamField path="product_public_id" type="string" required>
  The parent product's public ID, prefixed `prd_`.
</ParamField>

### Request Body

<ParamField body="sku" type="string" required>
  Stock-keeping unit identifier. Must be unique across all variants platform-wide. Between 1 and 80 characters.
</ParamField>

<ParamField body="price" type="string" required>
  Retail price as a decimal string matching `^\d{1,10}(\.\d{1,2})?$`. Example: `"99.99"`. Never use a float.
</ParamField>

<ParamField body="barcode" type="string">
  Barcode or UPC. Maximum 255 characters.
</ParamField>

<ParamField body="color" type="string">
  Color label, e.g. `"Black"`. Maximum 50 characters.
</ParamField>

<ParamField body="size" type="string">
  Size label, e.g. `"42"` or `"XL"`. Maximum 50 characters.
</ParamField>

<ParamField body="cost_price" type="string">
  Cost price as a decimal string. Used for margin calculations; not exposed to customers.
</ParamField>

<ParamField body="discount_percentage" type="string">
  Discount applied to `price` when computing `final_price`. Decimal string between `"0.00"` and `"100.00"`.
</ParamField>

<ParamField body="weight" type="string">
  Weight as a decimal string. Unit determined by your store configuration.
</ParamField>

<ParamField body="length" type="string">
  Length dimension as a decimal string.
</ParamField>

<ParamField body="width" type="string">
  Width dimension as a decimal string.
</ParamField>

<ParamField body="height" type="string">
  Height dimension as a decimal string.
</ParamField>

<ParamField body="status" type="string" default="DRAFT">
  Initial lifecycle status. One of `ACTIVE`, `DRAFT`, `INACTIVE`, `ARCHIVED`. Defaults to `DRAFT`.
</ParamField>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  # Step 1: get CSRF token
  TOKEN=$(curl -s -X GET https://api.example.com/api/v1/auth/csrf-token \
    -H "Cookie: session=<your-session-cookie>" \
    | jq -r '.data.csrf_token')

  # Step 2: create variant
  curl -X POST https://api.example.com/api/v1/admin/products/prd_01H/variants \
    -H "Content-Type: application/json" \
    -H "Cookie: session=<your-session-cookie>" \
    -H "x-csrf-token: $TOKEN" \
    -d '{
      "sku": "RUN-001-BLK-42",
      "price": "99.99",
      "color": "Black",
      "size": "42",
      "discount_percentage": "10.00",
      "weight": "0.35",
      "status": "DRAFT"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    'https://api.example.com/api/v1/admin/products/prd_01H/variants',
    {
      method: 'POST',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        'x-csrf-token': csrfToken,
      },
      body: JSON.stringify({
        sku: 'RUN-001-BLK-42',
        price: '99.99',
        color: 'Black',
        size: '42',
        discount_percentage: '10.00',
        weight: '0.35',
        status: 'DRAFT',
      }),
    }
  );
  const data = await response.json();
  ```
</CodeGroup>

### 201 Response

```json theme={null}
{
  "success": true,
  "data": {
    "public_id": "var_01H",
    "sku": "RUN-001-BLK-42",
    "barcode": null,
    "color": "Black",
    "size": "42",
    "price": "99.99",
    "cost_price": null,
    "discount_percentage": "10.00",
    "final_price": "89.99",
    "weight": "0.35",
    "length": null,
    "width": null,
    "height": null,
    "status": "DRAFT",
    "deleted_at": null,
    "created_at": "2024-06-01T09:05:00.000Z",
    "updated_at": "2024-06-01T09:05:00.000Z"
  }
}
```

<Note>
  SKU values must be unique across all variants in the entire platform, not just within a single product. Attempting to create a variant with a duplicate SKU returns a `409 Conflict`. Plan your SKU naming scheme (e.g. `BRAND-MODEL-COLOR-SIZE`) to avoid collisions.
</Note>

### Error Responses

| Status | Meaning                                                                                 |
| ------ | --------------------------------------------------------------------------------------- |
| `400`  | Validation error — invalid decimal format, bad status value, or missing required field. |
| `401`  | No active session.                                                                      |
| `403`  | Insufficient role.                                                                      |
| `409`  | A variant with this SKU already exists.                                                 |

***

## Get Variant

Fetch a single variant by its public ID within a product.

```
GET /admin/products/{product_public_id}/variants/{variant_public_id}
```

### Path Parameters

<ParamField path="product_public_id" type="string" required>
  The parent product's public ID, prefixed `prd_`.
</ParamField>

<ParamField path="variant_public_id" type="string" required>
  The variant's public ID, prefixed `var_`.
</ParamField>

Returns the full variant object. Responds with `404` if the product or variant does not exist.

***

## Update Variant

Partially update a variant's fields. Only the fields you supply are changed. Pass `null` for any nullable optional field — `barcode`, `color`, `size`, `cost_price`, `weight`, `length`, `width`, `height` — to explicitly clear it.

```
PATCH /admin/products/{product_public_id}/variants/{variant_public_id}
```

### Path Parameters

<ParamField path="product_public_id" type="string" required>
  The parent product's public ID, prefixed `prd_`.
</ParamField>

<ParamField path="variant_public_id" type="string" required>
  The variant's public ID, prefixed `var_`.
</ParamField>

### Request Body

At least one field is required. All fields from the create request are accepted, plus all nullable fields can be set to `null` to clear them.

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH \
    https://api.example.com/api/v1/admin/products/prd_01H/variants/var_01H \
    -H "Content-Type: application/json" \
    -H "Cookie: session=<your-session-cookie>" \
    -H "x-csrf-token: $TOKEN" \
    -d '{
      "status": "ACTIVE",
      "price": "89.99",
      "discount_percentage": "0.00"
    }'
  ```

  ```javascript Node.js theme={null}
  await fetch(
    'https://api.example.com/api/v1/admin/products/prd_01H/variants/var_01H',
    {
      method: 'PATCH',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        'x-csrf-token': csrfToken,
      },
      body: JSON.stringify({
        status: 'ACTIVE',
        price: '89.99',
        discount_percentage: '0.00',
      }),
    }
  );
  ```
</CodeGroup>

***

## Delete Variant

Soft-delete a variant. The variant is immediately hidden from customer views but is retained in the database so that existing order line items continue to reference the correct SKU and price snapshots. Returns `204 No Content` on success.

```
DELETE /admin/products/{product_public_id}/variants/{variant_public_id}
```

### Path Parameters

<ParamField path="product_public_id" type="string" required>
  The parent product's public ID, prefixed `prd_`.
</ParamField>

<ParamField path="variant_public_id" type="string" required>
  The variant's public ID, prefixed `var_`.
</ParamField>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE \
    https://api.example.com/api/v1/admin/products/prd_01H/variants/var_01H \
    -H "Cookie: session=<your-session-cookie>" \
    -H "x-csrf-token: $TOKEN"
  ```

  ```javascript Node.js theme={null}
  await fetch(
    'https://api.example.com/api/v1/admin/products/prd_01H/variants/var_01H',
    {
      method: 'DELETE',
      credentials: 'include',
      headers: { 'x-csrf-token': csrfToken },
    }
  );
  ```
</CodeGroup>

### Error Responses

| Status | Meaning                       |
| ------ | ----------------------------- |
| `401`  | No active session.            |
| `403`  | Insufficient role.            |
| `404`  | Product or variant not found. |
