Creating inventory items
Inventory item types, prices, VAT, tags, visibility and existing-reference relationships.
Use POST /api/v1/inventory to create an item and PUT /api/v1/inventory/{id} to update it. Send camelCase property names, an X-API-Key with inventory.create or inventory.update, and the location you are acting for in X-Location-Id. The REST reference lists every property you can write and every property an item is returned with, each with a description. A returned property is writable only if the write schema lists it; any other key in a write request is ignored, not stored and not reported as an error.
A minimal item
This request creates a regular 51.00 SEK item with 12% VAT and nothing else. Replace the location ID with an accessible location:
{
"locationId": 123,
"title": "Example coffee",
"itemType": "regular",
"pricings": [{ "name": "BASE", "price": 51, "order": 0 }],
"vatValue": 12
}No tags, category, modifier groups or visibility are needed for an item to have a price and VAT.
Item type
itemType is a catalogue classification string of at most 50 characters. It is not a closed enum: any string is stored unchanged, including "". Only recognised values carry behaviour:
| Value | Effect |
|---|---|
regular | An ordinary, separately sold product. Use this unless another value applies. null and "" behave the same. |
variant | A sub-product that exists only as an option of another product (a modifier choice). It is left out of delivery-marketplace menus and can be hidden from POS search. |
delivery | A shipping-fee product, selectable as the fee for storefront deliveries. |
gift_card | Each sale issues a gift card for the line amount. Where an integration provides the location's gift cards, the sale loads the integration's card instead. |
Any other string is stored and returned but changes nothing. Creating an item requires the property; it may be empty.
Three similarly named fields have different contracts:
| Field | Contract |
|---|---|
Inventory itemType / items.item_type | Catalogue string, described above. |
Legacy item_meta_data.item_type_key | Reference to the legacy item-type dictionary; not written by the inventory itemType input. |
BigQuery purchase_line_items.item_type | Recorded sales-line classification; see the goods export rules. Not interchangeable with catalogue type. |
Price
Set the price with pricings or an existing pricingGroupId, then read the item back to check calculatedPrice. basePrice is accepted on create for older clients but ignored.
pricings is a list of rules applied in order, each starting from the result of the one before. price is in currency units: 51 means 51.00 SEK in an SEK location.
name | Effect | metadata |
|---|---|---|
BASE | Sets the price to price. Use one BASE rule for a plain price. | none |
FIXED | Sets the price to price, or adds price to it with mode: "relative". | mode: absolute (default) or relative |
PERCENT | Changes the price by percentage percent. | percentage, and optionally maxAdjustment, minPrice, maxPrice in minor units |
FORMULA | Sets the price to the result of formula. | formula, and optionally variables |
Any other name is stored but does not change the price. scheduleId limits a rule to a schedule and channelTypes to channels (for example ["POS"]); with neither, the rule always applies. On update, pricings replaces the item's rules; send a rule's id back to keep its ID.
A pricingGroupId links an existing shared price instead of the item's own rules; it is unrelated to variantGroupIds, which link modifier/option groups.
VAT
Set VAT with vatId (an ID from GET /api/v1/vat-rates) or vatValue. If both are sent, vatId wins.
vatValue has different units on write and read:
| Direction | Unit | 12% is sent/returned as |
|---|---|---|
Write (POST, PUT) | percentage, 0–100 | 12 |
Read (GET) | basis points | 1200 |
So never send back the vatValue you read; use the returned vatId instead. Writes reject values above 100.
VAT is not required to save a price. When a create request has no vatId, vatValue or accountIds, the item gets the location country's default VAT, which is often wrong for the product (for example food versus alcohol), so set it explicitly. takeawayVatId is a separate rate used when the line is sold as takeaway.
Tags
Send tags as an object keyed by tag type:
{ "CATEGORY_PRIMARY": ["DRINK"], "ALLERGEN": ["NUTS"], "CUSTOM": ["oat-milk"] }- Tags are references, not upserts. Tag types and tag keys must already exist. Unknown ones are skipped silently: the request still succeeds and nothing is created. List category tags with
GET /api/v1/category-tags; create a custom tag first withPOST /api/v1/custom-tags. Read the item back to confirm which tags were attached. CUSTOMresolves existing custom tags in theCUISINEcustom-tag category.tagsreplaces. When an update includestags, every non-custom tag type you leave out is removed,CATEGORY_PRIMARYincluded. To change allergens without losing the category, send both. OmitCUSTOMto keep custom tags;CUSTOM: []clears them.- No tag is required for price or VAT.
CATEGORY_PRIMARYgroups the item in reports and analytics. - The legacy string-array shape (
["DRINK"]) passes validation but matches no tag type, so it removes every non-custom tag. Use the object shape.
Visibility
visibility (POS, KIOSK, TAKEAWAY, ONLINE, GENERAL) is a legacy field. It is stored but nothing reads it: it does not change where the item is sold, and it is not returned when you read the item. To control where an item can be ordered, use:
- channel availability in the menu layouts (returned on the item as
channelAvailability), POST /api/v1/inventory/{itemId}/availabilitywithACTIVATEorDEACTIVATEto put the item on or take it off sale everywhere,allowedTabTypesto limit the kinds of tab it can be ordered onto.
isAvailable on the item reports the result. Sending isAvailable in a create or update request has no effect.
Existing references
variantGroupIds, printerGroupIds, accountIds, servingCenterId, pricingGroupId, vatId and takeawayVatId all reference existing resources; none of them creates one. Create or look up the referenced resource first. On update, a supplied array replaces the item's links and [] removes them.
vatValue is the one exception: it finds the VAT rate with that value, creating it if needed.
Free-form objects
Every write property is listed in the reference, and any other key is ignored. Two properties are deliberately free-form, and the reference shows them as such:
metadatais yours. Karma stores it as you send it, returns it unchanged and reads none of its keys. Put your own identifiers here, prefixed with your company or system name; keys are case-sensitive, and keep article numbers as strings to preserve leading zeros. Never store secrets.contextholds settings for particular kinds of item. Its public key isgift_card, the settings of agift_carditem (amounts, card types, fees). Karma's own systems keep other keys in it, so treat it as read-modify-write: an update replaces the whole object.
Updates
An update changes only the properties it includes. Relationship arrays, pricings, tags, context and metadata replace what is stored. To merge selected top-level metadata keys instead, use PATCH /api/v1/inventory/{id}/metadata.
Reading items
GET /api/v1/inventory (list) and GET /api/v1/inventory/{id} (single item) return the same item, with a few properties only on one of them; the reference marks those "List endpoint only" or "Single-item GET only". posIntegration appears only when the location has a POS integration. Money is in currency units, except properties ending in Cents, which are minor units (öre). The exception is ministockCents: stock in hundredths of a unit, not money.