Overview & Creating a Product
Products are central to most API operations; they appear as line items on invoices, invoice-receipts, credit notes and other documents. This guide covers the product model and walks through creating products with various configurations.
Product types
Every product has a type that determines its behavior:
| Type | Value | Description |
|---|---|---|
| Product | 1 | A physical or tangible item. Can track stock. |
| Service | 2 | An intangible service. Cannot track stock. |
| Other | 3 | Any other type. Cannot track stock. |
Required fields
The ProductInsert input requires:
| Field | Type | Description |
|---|---|---|
name | String! | Product name |
reference | String! | Any sort of identifier you want to use (unique per company) |
type | Int! | 1 = Product, 2 = Service, 3 = Other |
productCategoryId | Int! | Category the product belongs to |
measurementUnitId | Int! | Unit of measure (e.g. units, kg, hours) |
Fetching prerequisites
Before creating a product, you need a category and a measurement unit.
Product categories
query {
productCategories(companyId: 1, options: {
search: { field: ALL, value: "Furniture" }
pagination: { page: 1, qty: 10 }
}) {
data {
productCategoryId
name
}
}
}
Measurement units
query {
measurementUnits(companyId: 1, options: {
pagination: { page: 1, qty: 50 }
}) {
data {
measurementUnitId
name
abbreviation
}
}
}
Creating a simple product
A minimal product with just the required fields:
mutation {
productCreate(
companyId: 1
data: {
name: "Office Chair"
reference: "CHAIR-001"
type: 1
productCategoryId: 5
measurementUnitId: 1
price: 149.99
}
) {
errors { field msg }
data {
productId
name
reference
price
}
}
}
Taxes
Products can have one or more taxes applied to them. Each tax has an ordering that determines the calculation sequence, and a cumulative flag that controls whether the tax is applied on top of the previously calculated tax.
Fetching available taxes
query {
taxes(companyId: 1, options: {
pagination: { page: 1, qty: 50 }
}) {
data {
taxId
name
value
type
fiscalZone
}
}
}
Creating with taxes
mutation {
productCreate(
companyId: 1
data: {
name: "Office Chair"
reference: "CHAIR-001"
type: 1
productCategoryId: 5
measurementUnitId: 1
price: 149.99
taxes: [
{
taxId: 1
value: 23
ordering: 1
cumulative: false
}
]
}
) {
errors { field msg }
data {
productId
taxes {
taxId
value
ordering
cumulative
}
}
}
}
The ordering field determines the sequence in which taxes are applied. When cumulative is true, the tax is calculated on the price plus previously applied taxes rather than on the base price alone.
Stock management
Products of type: 1 can track stock. Enable it with hasStock: true.
Default warehouse
Set warehouseId to assign a default warehouse, and provide an initial stock level via warehouses:
mutation {
productCreate(
companyId: 1
data: {
name: "Office Chair"
reference: "CHAIR-001"
type: 1
productCategoryId: 5
measurementUnitId: 1
price: 149.99
hasStock: true
warehouseId: 1
warehouses: [
{
warehouseId: 1
stock: 50
minStock: 5
}
]
}
) {
errors { field msg }
data {
productId
hasStock
stock
warehouses {
warehouseId
stock
minStock
}
}
}
}
Multi-warehouse stock
A product can have stock in multiple warehouses:
warehouses: [
{ warehouseId: 1, stock: 50, minStock: 5 },
{ warehouseId: 2, stock: 30, minStock: 3 }
]
Price classes
Price classes let you define different prices for different customer groups (e.g. wholesale vs retail). Each entry maps a priceClassId to a specific price.
mutation {
productCreate(
companyId: 1
data: {
name: "Office Chair"
reference: "CHAIR-001"
type: 1
productCategoryId: 5
measurementUnitId: 1
price: 149.99
priceClasses: [
{ priceClassId: 1, value: 129.99 },
{ priceClassId: 2, value: 109.99 }
]
}
) {
errors { field msg }
data {
productId
price
priceClasses {
priceClassId
value
}
}
}
}
Suppliers
Associate one or more suppliers with cost prices:
suppliers: [
{
supplierId: 10
costPrice: 75.00
reference: "SUP-CHAIR-001"
}
]
| Field | Type | Description |
|---|---|---|
supplierId | Int! | The supplier ID |
costPrice | Float! | Purchase cost per unit |
reference | String | The supplier's identifier |
Identifications (barcodes)
Products can have barcodes or other identifiers attached:
identifications: [
{ type: 2, text: "5601234567890", favorite: true }
]
The type field maps to a barcode format:
| Type | Format |
|---|---|
1 | EAN8 |
2 | EAN13 |
3 | JAN13 |
4 | ISSN |
5 | ISBN |
6 | UPCA |
7 | UPCE |
8 | CODE39 |
9 | CODE93 |
10 | DATAMATRIX |
11 | PDF417 |
12 | QRCODE |
The favorite flag marks the primary barcode shown at a glance.
Optional fields
Beyond the examples above, ProductInsert supports:
| Field | Type | Description |
|---|---|---|
summary | String | Short description |
notes | String | Internal notes |
notesOnExport | Boolean | Include notes when exporting documents |
visible | Int | Visibility flag (default: 1) |
exemptionReason | String | Tax exemption reason |
img | Upload | Product image |
customFields | [ProductCustomField!] | Dynamic custom field values |
See the full ProductInsert reference for all options.
Querying products
Single product
query {
product(companyId: 1, productId: 100) {
data {
productId
name
reference
price
type
hasStock
stock
productCategory { name }
measurementUnit { name abbreviation }
taxes {
taxId
value
ordering
}
warehouses {
warehouseId
stock
minStock
}
}
}
}
Listing products
query {
products(companyId: 1, options: {
search: { field: ALL, value: "Chair" }
order: { field: NAME, sort: ASC }
pagination: { page: 1, qty: 20 }
}) {
data {
productId
name
reference
price
stock
}
options {
pagination {
page
qty
count
}
}
}
}
See the pagination and filtering guides for more on list queries.
Updating a product
Use productUpdate to modify an existing product. Only the productId is required; include only the fields you want to change:
mutation {
productUpdate(
companyId: 1
data: {
productId: 100
price: 159.99
notes: "Price increased for 2025"
}
) {
errors { field msg }
data {
productId
price
notes
}
}
}
Next steps
- Property Groups: Define properties like Color and Size for your products
- Variants: Create and manage product variants using property groups
- See the full
ProductInsertandProductReadreference pages