# Create new product

`POST /accounts/{accountID}/products`

API version: `v2026.10.00`. Send `X-Moov-Version: v2026.10.00` to get the behavior described here.

> AI agents: search and read all Moov docs with the docs MCP server at https://docs.moov.io/mcp (no API key). Setup: https://docs.moov.io/guides/developer-tools/mcp-ai/docs-mcp/index.md

Creates a new product for the specified account.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `X-Moov-Version` | header | string |  | Set this header to v2026.10.00 to use the API described in this specification. When omitted, the server defaults to v2024.01.00, the earliest supported version, which may not match the behavior documented here. An unrecognized well-formed version uses the latest supported version that is not newer than the requested version, when one exists. For example, `v2026.08.00` uses `v2026.07.00`. A malformed value, such as `2022`, returns a `404` response. Values: `v2026.10.00`. |
| `accountID` | path | string | Yes |  |

## Request body

Content type: `application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes |  |
| `description` | string |  | A detailed description of the product. - Must be valid UTF-8 text - Supports Markdown for formatting - HTML is not permitted and will be rejected |
| `basePrice` | object | Yes | A product's starting price, before applying modifiers. |
| `basePrice.currency` | string | Yes | A 3-letter ISO 4217 currency code. |
| `basePrice.valueDecimal` | string | Yes | A decimal-formatted numerical string that represents up to 9 decimal place precision. For example, $12.987654321 is '12.987654321'. |
| `isTaxable` | boolean |  | Whether applicable tax rules may be applied to this product. The value can be used to determine how to populate the tax amount on a transfer (Moov does not compute or assess tax). true means a tax amount can be included; false means it should not. Omitted values default to true on creation and preserve the existing setting on update. This setting does not determine jurisdiction-specific taxability. |
| `images` | array of object |  | Assign previously uploaded images to a product or option. |
| `images[].imageID` | string | Yes | Unique identifier for a product or product option image resource. |
| `optionGroups` | array of object |  | Optional configuration options for a product, such as size or color. |
| `optionGroups[].name` | string | Yes |  |
| `optionGroups[].description` | string |  | A detailed description of the option group. - Must be valid UTF-8 text - Supports Markdown for formatting - HTML is not permitted and will be rejected |
| `optionGroups[].minSelect` | integer (int32) | Yes | The minimum number of options that must be selected from this group. A value of 0 indicates that no selection from this group is required. |
| `optionGroups[].maxSelect` | integer (int32) | Yes | The maximum number of options that can be selected from this group. |
| `optionGroups[].options` | array of object | Yes | The options available within this group. |
| `optionGroups[].options[].name` | string | Yes | The display name of a product option. |
| `optionGroups[].options[].description` | string |  | A detailed description of the option. - Must be valid UTF-8 text - Supports Markdown for formatting - HTML is not permitted and will be rejected |
| `optionGroups[].options[].priceModifier` | object |  | The adjustment applied to a product's base price by this option. Can be negative, positive, or zero. |
| `optionGroups[].options[].priceModifier.currency` | string | Yes | A 3-letter ISO 4217 currency code. |
| `optionGroups[].options[].priceModifier.valueDecimal` | string | Yes | A decimal-formatted numerical string that represents up to 9 decimal place precision. For example, $12.987654321 is '12.987654321'. |
| `optionGroups[].options[].images` | array of object |  | Assign previously uploaded images to a product or option. |
| `optionGroups[].options[].images[].imageID` | string | Yes | Unique identifier for a product or product option image resource. |
| `categoryID` | string |  | The ID of a product taxonomy category to associate with the product. |

Example:

```json
{
  "title": "World's best lemonade",
  "description": "Really, the best.",
  "basePrice": {
    "valueDecimal": "4.99",
    "currency": "USD"
  },
  "images": [
    {
      "imageID": "fed91252-6f48-4b70-885e-520bf53a52ff"
    },
    {
      "imageID": "eb466644-0a58-4b87-af1e-94d03e223ad2"
    }
  ],
  "optionGroups": [
    {
      "name": "Flavor add-ins",
      "description": "Choose up to 3 flavor add-ins to enhance your lemonade.",
      "minSelect": 0,
      "maxSelect": 3,
      "options": [
        {
          "name": "Strawberry puree",
          "description": "Fresh and fruity.",
          "priceModifier": {
            "valueDecimal": "0.99",
            "currency": "USD"
          },
          "images": [
            {
              "imageID": "d359808d-9896-4414-8d17-dac43f35842d"
            }
          ]
        },
        {
          "name": "Passionfruit syrup",
          "priceModifier": {
            "valueDecimal": "0.49",
            "currency": "USD"
          }
        },
        {
          "name": "Cherry syrup",
          "priceModifier": {
            "valueDecimal": "0.49",
            "currency": "USD"
          }
        }
      ]
    },
    {
      "name": "Sweetener",
      "description": "Choose a sweetener for your lemonade.",
      "minSelect": 1,
      "maxSelect": 1,
      "options": [
        {
          "name": "Cane Sugar"
        },
        {
          "name": "Honey",
          "priceModifier": {
            "valueDecimal": "0.99",
            "currency": "USD"
          }
        },
        {
          "name": "Stevia",
          "description": "Natural, zero-calorie sweetener."
        }
      ]
    }
  ]
}
```

## Response 201

The resource was successfully created.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `productID` | string | Yes | Unique identifier for a product. |
| `title` | string | Yes |  |
| `description` | string |  | A detailed description of the product. - Must be valid UTF-8 text - Supports Markdown for formatting - HTML is not permitted and will be rejected |
| `basePrice` | object | Yes | A product's starting price, before applying modifiers. |
| `basePrice.currency` | string | Yes | A 3-letter ISO 4217 currency code. |
| `basePrice.valueDecimal` | string | Yes | A decimal-formatted numerical string that represents up to 9 decimal place precision. For example, $12.987654321 is '12.987654321'. |
| `isTaxable` | boolean | Yes | Whether applicable tax rules may be applied to this product. The value can be used to determine how to populate the tax amount on a transfer (Moov does not compute or assess tax). true means a tax amount can be included; false means it should not. Omitted values default to true on creation and preserve the existing setting on update. This setting does not determine jurisdiction-specific taxability. |
| `optionGroups` | array of object |  | Optional configuration options for a product, such as size or color. |
| `optionGroups[].name` | string | Yes |  |
| `optionGroups[].description` | string |  | A detailed description of the option group. - Must be valid UTF-8 text - Supports Markdown for formatting - HTML is not permitted and will be rejected |
| `optionGroups[].minSelect` | integer (int32) | Yes | The minimum number of options that must be selected from this group. A value of 0 indicates that no selection from this group is required. |
| `optionGroups[].maxSelect` | integer (int32) | Yes | The maximum number of options that can be selected from this group. |
| `optionGroups[].options` | array of object | Yes | The options available within this group. |
| `images` | array of object |  | Optional images associated with the product. |
| `images[].imageID` | string | Yes | Unique identifier for a product or product option image resource. |
| `images[].altText` | string |  | Alternative text for the image. |
| `images[].link` | string (uri) | Yes | The image's public URL. |
| `images[].publicID` | string | Yes | The public ID used to access the image. |
| `category` | object |  | The product taxonomy category associated with the product, if any. |
| `category.categoryID` | string | Yes | The unique identifier for the category. |
| `category.name` | string | Yes | The short display name of the category. |
| `category.fullName` | string | Yes | The full taxonomy path name of the category. |
| `category.level` | integer (int32) | Yes | The depth of the category in the taxonomy tree (1 = top-level). |
| `category.parentID` | string |  | The identifier of the parent category, if any. Absent for top-level categories. |
| `createdOn` | string (date-time) | Yes | The date and time when the product was added. |
| `updatedOn` | string (date-time) | Yes | The date and time when the product was last updated. |
| `disabledOn` | string (date-time) |  | The date and time when the product was disabled. |

## Errors

| Status | Meaning |
| --- | --- |
| 400 | The server could not understand the request due to invalid syntax. |
| 401 | The request contained missing or expired authentication. |
| 403 | The user is not authorized to make the request. |
| 404 | The requested resource was not found. |
| 409 | The request conflicted with the current state of the target resource. |
| 422 | The request was well-formed, but the contents failed validation. Check the request for missing or invalid fields. |
| 429 | Request was refused due to rate limiting. |
| 500 | The request failed due to an unexpected error. |
| 504 | The request failed because a downstream service failed to respond. |

## Examples

### cURL

```bash
curl -X POST "https://api.moov.io/accounts/{accountID}/products" \
  -H "Authorization: Bearer {token}" \
  -H "X-Moov-Version: v2026.10.00" \
  -d '{
  "title": "World'"'"'s best lemonade",
  "description": "Really, the best.",
  "basePrice": {
    "valueDecimal": "4.99",
    "currency": "USD"
  },
  "images": [
    {
      "imageID": "fed91252-6f48-4b70-885e-520bf53a52ff"
    },
    {
      "imageID": "eb466644-0a58-4b87-af1e-94d03e223ad2"
    }
  ],
  "optionGroups": [
    {
      "name": "Flavor add-ins",
      "description": "Choose up to 3 flavor add-ins to enhance your lemonade.",
      "minSelect": 0,
      "maxSelect": 3,
      "options": [
        {
          "name": "Strawberry puree",
          "description": "Fresh and fruity.",
          "priceModifier": {
            "valueDecimal": "0.99",
            "currency": "USD"
          },
          "images": [
            {
              "imageID": "d359808d-9896-4414-8d17-dac43f35842d"
            }
          ]
        },
        {
          "name": "Passionfruit syrup",
          "priceModifier": {
            "valueDecimal": "0.49",
            "currency": "USD"
          }
        },
        {
          "name": "Cherry syrup",
          "priceModifier": {
            "valueDecimal": "0.49",
            "currency": "USD"
          }
        }
      ]
    },
    {
      "name": "Sweetener",
      "description": "Choose a sweetener for your lemonade.",
      "minSelect": 1,
      "maxSelect": 1,
      "options": [
        {
          "name": "Cane Sugar"
        },
        {
          "name": "Honey",
          "priceModifier": {
            "valueDecimal": "0.99",
            "currency": "USD"
          }
        },
        {
          "name": "Stevia",
          "description": "Natural, zero-calorie sweetener."
        }
      ]
    }
  ]
}'
```

### Typescript (SDK)

```typescript
import { Moov } from "@moovio/sdk";

const moov = new Moov({
  security: {
    username: "",
    password: "",
  },
});

async function run() {
  const result = await moov.products.create({
    accountID: "27cd3181-7c1c-4d81-b020-e7d55c33941f",
    productRequest: {
      title: "World's best lemonade",
      description: "Really, the best.",
      basePrice: {
        currency: "USD",
        valueDecimal: "4.99",
      },
      images: [
        {
          imageID: "fed91252-6f48-4b70-885e-520bf53a52ff",
        },
        {
          imageID: "eb466644-0a58-4b87-af1e-94d03e223ad2",
        },
      ],
      optionGroups: [
        {
          name: "Flavor add-ins",
          description: "Choose up to 3 flavor add-ins to enhance your lemonade.",
          minSelect: 0,
          maxSelect: 3,
          options: [
            {
              name: "Strawberry puree",
              description: "Fresh and fruity.",
              priceModifier: {
                currency: "USD",
                valueDecimal: "0.99",
              },
              images: [
                {
                  imageID: "d359808d-9896-4414-8d17-dac43f35842d",
                },
              ],
            },
            {
              name: "Passionfruit syrup",
              priceModifier: {
                currency: "USD",
                valueDecimal: "0.49",
              },
            },
            {
              name: "Cherry syrup",
              priceModifier: {
                currency: "USD",
                valueDecimal: "0.49",
              },
            },
          ],
        },
        {
          name: "Sweetener",
          description: "Choose a sweetener for your lemonade.",
          minSelect: 1,
          maxSelect: 1,
          options: [
            {
              name: "Cane Sugar",
            },
            {
              name: "Honey",
              priceModifier: {
                currency: "USD",
                valueDecimal: "0.99",
              },
            },
            {
              name: "Stevia",
              description: "Natural, zero-calorie sweetener.",
            },
          ],
        },
      ],
    },
  });

  console.log(result);
}

run();
```

Full reference with SDK examples in every language: https://docs.moov.io/api/v2026.10.00/tools/products/post/
