---
title: "Create Product"
method: POST
path: "/api/v1/products"
tags: ["products"]
---

# Create Product

`POST /api/v1/products`

## Request

- Base URL: `https://demo.invoiceninja.com`
- URL: `https://demo.invoiceninja.com/api/v1/products`
- Auth: none declared. Required headers: `X-API-TOKEN`, `X-Requested-With`
- TypeScript: <https://skmtc.dev/invoiceninja/apis/invoice-ninja-api-reference/docs/api/v1/products/post.ts> (a function with typed inputs; its response is checked against the schema)

##  POST /api/v1/products
Adds a product to a company

## Query parameters

- `include` string

## Headers

- `X-API-TOKEN` string, required
- `X-Requested-With` string, required

## Request body

- ProductRequest
  - `assigned_user_id` string: The hashed ID of the user assigned to this product.
  - `project_id` string: The hashed ID of the project that this product is associated with.
  - `vendor_id` string: The hashed ID of the vendor that this product is associated with.
  - `custom_value1` string: Custom value field 1.
  - `custom_value2` string: Custom value field 2.
  - `custom_value3` string: Custom value field 3.
  - `custom_value4` string: Custom value field 4.
  - `product_key` string: The product key.
  - `notes` string: Notes about the product.
  - `cost` number, double: The cost of the product.
  - `price` number, double: The price of the product.
  - `quantity` number, double: The quantity of the product.
  - `tax_name1` string: The default tax name associated with this product
  - `tax_rate1` number, double: The default tax rate for this product
  - `tax_name2` string: The default tax name associated with this product
  - `tax_rate2` number, double: The default tax rate for this product
  - `tax_name3` string: The default tax name associated with this product
  - `tax_rate3` number, double: The default tax rate for this product
  - `in_stock_quantity` integer: The quantity of the product that is currently in stock. **note** this field is not mutable without passing an extra query parameter which will allow modification of this value. The query parameter ?update_in_stock_quantity=true **MUST** be passed if you wish to update this value manually.
  - `stock_notification` boolean: Indicates whether stock notifications are enabled for this product
  - `stock_notification_threshold` integer: The minimum quantity threshold for which stock notifications will be triggered
  - `max_quantity` integer: The maximum quantity that can be ordered for this product
  - `product_image` string, uri-reference: The URL of the product image
  - `tax_id` string: The tax category id for this product.' The following constants are available (default = '1') ``` PRODUCT_TYPE_PHYSICAL = '1' PRODUCT_TYPE_SERVICE = '2' PRODUCT_TYPE_DIGITAL = '3' PRODUCT_TYPE_SHIPPING = '4' PRODUCT_TYPE_EXEMPT = '5' PRODUCT_TYPE_REDUCED_TAX = '6' PRODUCT_TYPE_OVERRIDE_TAX = '7' PRODUCT_TYPE_ZERO_RATED = '8' PRODUCT_TYPE_REVERSE_TAX = '9' ```
  - `income_account_id` string: The accounting income account identifier this product maps to (used by external accounting integrations such as QuickBooks).

## Response `200`

Returns the saved product object

- Product
  - `id` string: The hashed product ID.
  - `user_id` string: The hashed ID of the user that created this product.
  - `assigned_user_id` string: The hashed ID of the user assigned to this product.
  - `project_id` string: The hashed ID of the project that this product is associated with.
  - `vendor_id` string: The hashed ID of the vendor that this product is associated with.
  - `custom_value1` string: Custom value field 1.
  - `custom_value2` string: Custom value field 2.
  - `custom_value3` string: Custom value field 3.
  - `custom_value4` string: Custom value field 4.
  - `product_key` string: The product key.
  - `notes` string: Notes about the product.
  - `cost` number, double: The cost of the product. (Your purchase price for this product)
  - `price` number, double: The price of the product that you are charging.
  - `quantity` number, double: The quantity of the product. (used as a default)
  - `tax_name1` string: The name of tax 1.
  - `tax_rate1` number, double: The rate of tax 1.
  - `tax_name2` string: The name of tax 2.
  - `tax_rate2` number, double: The rate of tax 2.
  - `tax_name3` string: The name of tax 3.
  - `tax_rate3` number, double: The rate of tax 3.
  - `archived_at` integer: The timestamp when the product was archived.
  - `created_at` integer: The timestamp when the product was created.
  - `updated_at` integer: Timestamp
  - `is_deleted` boolean: Boolean flag determining if the product has been deleted
  - `in_stock_quantity` integer: The quantity of the product that is currently in stock
  - `stock_notification` boolean: Indicates whether stock notifications are enabled for this product
  - `stock_notification_threshold` integer: The minimum quantity threshold for which stock notifications will be triggered
  - `max_quantity` integer: The maximum quantity that can be ordered for this product
  - `product_image` string, uri-reference: The URL of the product image
  - `tax_id` string: The tax category id for this product.' The following constants are available (default = '1') ``` PRODUCT_TYPE_PHYSICAL = '1' PRODUCT_TYPE_SERVICE = '2' PRODUCT_TYPE_DIGITAL = '3' PRODUCT_TYPE_SHIPPING = '4' PRODUCT_TYPE_EXEMPT = '5' PRODUCT_TYPE_REDUCED_TAX = '6' PRODUCT_TYPE_OVERRIDE_TAX = '7' PRODUCT_TYPE_ZERO_RATED = '8' PRODUCT_TYPE_REVERSE_TAX = '9' ```
  - `income_account_id` string: The accounting income account identifier this product maps to (used by external accounting integrations such as QuickBooks).

## Other responses

- `401`: Authentication error
- `403`: Authorization error
- `422`: Validation error
- `429`: Rate Limit Exceeded
- `5XX`: Server error
- `default`: Unexpected Error

## Changes

- **2026-04-20** `69a36036d334`: 2 info
  - added the new optional request property `income_account_id`
  - added the optional property `income_account_id` to the response with the `200` status
- **2024-06-06** `8e82a2bd77e0`: 3 breaking, 56 info
  - the request's body type changed from no type to `object`
  - the response's body type changed from no type to `object` for status `200`
  - the response's body type changed from no type to `object` for status `default`
  - added the new optional request property `assigned_user_id`
  - …55 more
- **2024-06-05** `e61df65649e2`: 3 breaking, 56 warning
  - the request's body type changed from `object` to no type
  - the response's body type changed from `object` to no type for status `200`
  - the response's body type changed from `object` to no type for status `default`
  - removed the request property `assigned_user_id`
  - …55 more
- **2024-03-07** `71171a40d629`: 7 breaking, 63 info
  - the request's body type changed from no type to `object`
  - the response's body type changed from no type to `object` for status `200`
  - the response's body type changed from no type to `object` for status `401`
  - the response's body type changed from no type to `object` for status `403`
  - …66 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/invoiceninja/apis/invoice-ninja-api-reference/changes/api/v1/products/post.md)

---

[API](https://skmtc.dev/invoiceninja/apis/invoice-ninja-api-reference.md) - [All operations](https://skmtc.dev/invoiceninja/apis/invoice-ninja-api-reference/llms.txt) - [OpenAPI document](https://skmtc.dev/invoiceninja/apis/invoice-ninja-api-reference/revisions/bcda1f823746?raw)
