Catalog Entries

Managing catalog entries in Ottimate

A catalog entry represents an item from your inventory management system stored in Ottimate. Each catalog entry is associated with a specific vendor and company, enabling accurate invoice matching and price variance detection.

When catalog entries are successfully synchronized, Ottimate automatically matches invoice line items to catalog items and displays match suggestions, including pricing variances, in the item validation interface.

Item-Validation UI on the Ottimate Dashboard

Common Workflows

This guide covers four primary catalog management workflows that can be enabled via API.

  1. Syncing Catalog Data - Push inventory items from your system to Ottimate
  2. Fetching Purchased Items - Retrieve all invoice items matched to a catalog entry
  3. Fetching Matched Catalog Entries - Find which catalog entry an invoice item is matched to
  4. Location-based pricing - Sync location-specific prices (requires Ottimate setup)

Syncing Catalog Data

Syncing your inventory catalog to Ottimate enables automatic invoice matching and price variance detection. This workflow is designed for inventory management systems to maintain an up-to-date catalog in Ottimate.

Single Item Sync

Create a single catalog entry using POST /catalog/entries:

1POST /catalog/entries
2Content-Type: application/json
3
4{
5 "ottimate_company_id": 15196,
6 "erp_vendor_id": "9999",
7 "description": "HEINZ KC BBQ BAKED BEANS",
8 "sku": "SKU-BBB-001",
9 "upc": "1300001102",
10 "pack_size": "12.0/16 OZ",
11 "uom": "Case (C)",
12 "price": 19.500000,
13 "unit_price": 1.620000,
14 "reference_id": "1300001102"
15}

Response (201 Created):

1{
2 "id": "cte_12345",
3 "ottimate_company_id": 15196,
4 "reference_id": "1300001102",
5 "description": "HEINZ KC BBQ BAKED BEANS",
6 "sku": "SKU-BBB-001",
7 "pack_size": "12.0/16 OZ",
8 "uom": "Case (C)",
9 "price": 19.500000,
10 "unit_price": 1.620000,
11 "erp_vendor_id": "9999",
12 "ottimate_vendor_name": "Sysco Foods",
13 "display_name": "HEINZ KC BBQ BAKED BEANS - Sysco",
14 "created_date": "2024-12-05T10:30:00Z",
15 "last_modified_date": "2024-12-05T10:30:00Z"
16}

Required Fields

FieldTypeDescription
ottimate_company_idIntegerThe Ottimate-assigned company ID. Retrieve via GET /accounts/{id}/companies
erp_vendor_idStringERP-assigned vendor identifier. Must be consistent with the erp_vendor_id used to create an accounting vendor in Ottimate. Verify via GET /vendors
descriptionStringItem name/description. Populates “Item Name” in the UI and powers AI-based matching
reference_idStringYour system’s unique identifier for this item.

Including these fields significantly improves matching accuracy:

FieldTypeDescription
skuStringStock-Keeping Unit from your inventory system
upcString12-digit Universal Product Code. If Should always be provided if available to improve matching accuracy
pack_sizeStringPack size using format: {case size}/{unit size} (e.g., “12.0/16 OZ” indicates 12 units in the case, and each unit is 16 fluid ounces)
uomStringUnit of measure (e.g., “CASE”, “EA”, “LB”)
priceDecimalPack price in USD. Accepts decimals up to 5 digits. (e.g. 10.00000)
unit_priceDecimalPrice per individual unit within the pack.

For the full list of fields, see POST /catalog/entries.

Bulk Sync

For syncing large catalogs (1,000+ items), use the bulk endpoint POST /catalog/entries/bulk:

1POST /catalog/entries/bulk
2Content-Type: application/json
3
4{
5 "ottimate_company_id": 15196,
6 "entries": [
7 {
8 "erp_vendor_id": "9999",
9 "description": "HEINZ KC BBQ BAKED BEANS",
10 "sku": null,
11 "upc": "1300001102",
12 "pack_size": "12.0/16 OZ",
13 "uom": "Case (C)",
14 "price": 12.99,
15 "reference_id": "1300001102"
16 },
17 {
18 "erp_vendor_id": "9999",
19 "description": "BACON BITS PER LB",
20 "sku": null,
21 "upc": "23585000000",
22 "size": "1.0/LB",
23 uom": "Weight (W),
24 "price": 3.99,
25 "unique_key": "1300001102"
26 }
27 // ... up to 1000 entries per request
28 ]
29}

Response (201 Created):

1{
2 "success_count": 2,
3 "created_count": 1,
4 "updated_count": 1,
5 "error_count": 0,
6 "created": [
7 {
8 "id": "cte_12348",
9 "item_name": "HEINZ KC BBQ BAKED BEANS"
10 ...
11 }
12 ],
13 "updated": [
14 {
15 "id": "cte_12345",
16 "item_name": "BACON BITS PER LB"
17 ...
18 }
19 ],
20 "errors": []
21}

Understanding the upsert pattern for bulk operations

Bulk catalog synchronization uses an upsert (update or insert) pattern to prevent duplicates. Ottimate automatically generates a catalog_unique_key from the fields you provide:

When UPC is provided (Default behaviour):

catalog_unique_key = erp_vendor_id + upc

When UPC is not provided:

catalog_unique_key = erp_vendor_id + description + sku + pack_size

When you POST to /catalog/entries/bulk:

  • If the catalog_unique_key doesn’t exist → Creates a new catalog entry
  • If the catalog_unique_key exists → Updates the existing catalog entry

This lets you safely sync your entire catalog repeatedly without creating duplicates.

To avoid duplicating items through an upsert operation, keep erp_vendor_id ,description , size, uom, upc consitent, or use PATCH catalog/entries/{entry_id} to update entries individually.

Retrieving Catalog Entries

Before syncing, you may want to check what’s already in Ottimate:

List all entries for a company:

1GET /catalog/entries?ottimate_company_id=15196&limit=100

Search for specific items:

1GET /catalog/entries?ottimate_company_id=15196&search=tomato&erp_vendor_id=Sysco

Get full details for a specific entry:

1GET /catalog/entries/{id}

Use the expand parameter to include related pricing and allowance data:

1GET /catalog/entries/{id}?expand=prices,allowances

Fetching Purchased Items for a Catalog Entry

Once catalog entries are matched to invoice items, you can retrieve all purchased items associated with a specific catalog entry. This is useful for:

  • Analyzing purchase history for a specific catalog item
  • Identifying price variances over time

Endpoint

1GET /catalog/variances/{catalog_entry_id}/invoice-items

Example Request

1GET /catalog/variances/cte_12345/invoice-items?ottimate_company_id=15196

Response

1{
2 "count": 150,
3 "next": "https://api.ottimate.com/v1/catalog/variances/cte_12345/invoice-items?page=2",
4 "previous": null,
5 "results": [
6 {
7 "id": 821125897,
8 "invoice_id": 139851296,
9 "invoice_number": "I-1767901026-2",
10 "ottimate_location_id": 51582,
11 "item_name": "Sample Item 821125897",
12 "price": 1.200000,
13 "quantity": 28.000000,
14 "invoice_date": "2026-01-11",
15 "price_variance": 0.19999999999999996,
16 "effective_price": 1.1928571428571428
17 },
18 {
19 "id": 821125898,
20 "invoice_id": 139851297,
21 "invoice_number": "I-1767901026-2",
22 "ottimate_location_id": 51582,
23 "item_name": "Sample Item 821125897",
24 "price": 1.000000,
25 "quantity": 12.000000,
26 "invoice_date": "2026-01-04",
27 "price_variance": null,
28 "effective_price": 1.0
29 }
30 // ... more purchased items
31 ]
32}

Purchased Items

The result object includes purchased item objects with the following fields:

FieldDescription
idOttimate-generated ID for the invoice line item.
invoice_idOttimate-generated identifier for the invoice. Can be used to fetch invoice details through GET /invoices/{invoice_id}
invoice_numberVendor-issued Invoice Number extracted from the original invoice document
item_nameItem name extracted from the invoice
priceActual item price on the invoice
effective_priceActual item price - any applicable allowances and discounts
price_varianceOverbilling/underbilling depending on the difference between item price on the invoice, catalog price, adjusting for allowances.

Fetching Matched Catalog Entries for Purchased Items

When reviewing invoices, you may need to see which catalog entries are matched to invoice line items.

Invoice List with Expansion

Retrieve invoices with catalog matching information using the expand=items parameter. To set the expand parameter, you must also limit the date range to 30 days.

Note that only invoice items matched to a catalog entry will return a catalog entry object.

1GET /invoices?date_from=2025-12-15&date_to=2026-01-14&expand=items

Example Response

1{
2 "id": "124425480",
3 "invoice_number": "202601050949",
4 "type": "invoice",
5 "ottimate_vendor_name": "PETE-MA-01",
6 "ottimate_vendor_id": "833906",
7 "erp_vendor_id": "PETE-MA-01",
8 "ottimate_location_name": "Sample Location",
9 "ottimate_location_id": "48764",
10 "created_at": "2026-01-05T06:49:24.609646-08:00",
11 "invoice_date": "2026-01-05",
12 "due_date": "2026-01-30",
13 "total_amount": 155.00,
14 "total_tax": 0.00,
15 "status": "verified",
16 "payment_status": "unpaid",
17 "error": null,
18 "currency": "USD",
19 "outstanding_balance": 155.00,
20 "purchase_order": "",
21 "has_unmatched_items": null,
22 "approved_date": "2026-01-06T11:40:07.536994-08:00",
23 "exported_date": null,
24 "on_hold": {
25 "is_held": true,
26 "reason": ""
27 },
28 "posting_date": null,
29 "items": [
30 {
31 "line": "735920103",
32 "ottimate_item_id": "34551621",
33 "name": "t-shirt xl",
34 "display_name": "t-shirt xl",
35 "sku": "",
36 "type": "item",
37 "quantity": 1.0,
38 "unit": "Each",
39 "unit_price": 155.00,
40 "line_total": 155.00,
41 "charge_type": "",
42 "is_taxed": false,
43 "pack_size": null,
44 "uom": null,
45 "catalog_entry": {
46 "id": "cte_TQoHfgJ9S8mT",
47 "ottimate_company_id": 15365,
48 "reference_id": "pbwteelogoxl",
49 "catalog_unique_key": "petema01-pbwteelogoxl-10each-petesbwshoptshirtxl",
50 "description": "Pete's B&W Shop T-Shirt - XL",
51 "original_description": "Pete's B&W Shop T-Shirt - XL",
52 "sku": "PBW-TEE-LOGO-XL",
53 "upc": "",
54 "size": "1.0/Each",
55 "uom": "Each",
56 "price": 11.000000,
57 "unit_price": 11.000000,
58 "last_purchased_price": null,
59 "erp_vendor_id": "PETE-MA-01",
60 "ottimate_vendor_name": "",
61 "is_split_case": false,
62 "authorized_vendor": true,
63 "last_purchased_date": "",
64 "created_date": "2025-12-23T08:11:30.213448-08:00",
65 "last_modified_date": "2025-12-23T08:11:30.213432-08:00",
66 "dimensions": "",
67 "properties": "",
68 "display_name": "pete's b&w shop t-shirt - xl (PBW-TEE-LOGO-XL)",
69 "prices": "",
70 "allowances": ""
71 },
72 "custom_fields": {},
73 "dimensions": {}
74 }
75 ]
76 }
77}

Advanced Pricing Configurations

Setup Required: Location-specific pricing and allowances require additional configuration during client onboarding. Contact your Ottimate implementation team before using these features.

Location-Specific Prices

An Ottimate implementation may include setting up multiple locations. By default, catalog prices apply to all locations within a company. For clients with store-based pricing, you can set different prices for different Ottimate locations or location groups.

Configuration Requirements

Before implementing location-specific prices:

  1. Confirm the client company is configured for location-based catalog pricing
  2. Obtain the ottimate_location_id or ottimate_group_id values via GET /accounts/{account_id}/locations

Creating Location-Specific Prices

Include the prices array when creating catalog entries in place of the price field:

1POST /catalog/entries
2Content-Type: application/json
3
4{
5 "ottimate_company_id": 123456,
6 "erp_vendor_id": "PETE-MA-01",
7 "description": " Curry Paste Namya 1 kg",
8 "sku": "6340260",
9 "reference_id": "1341219125",
10 "upc": "1341219125",
11 "unit_price": 1.00,
12 "size":"12.0/1 kg",
13 "uom":"Case (C)",
14 "prices":[
15 {
16 "price":60.00000,
17 "price_type":"location",
18 "ottimate_location_id":123,
19 "start_date":"2025-12-23"
20 },
21 {
22 "price":61.00000,
23 "price_type":"location",
24 "ottimate_location_id":456,
25 "start_date":"2026-01-01"
26 }
27 ]
28}

Price Object Fields

FieldTypeRequiredDescription
priceDecimalYesPack price in USD for this location
unit_priceDecimalNoOptional unit price applicable to this location
ottimate_location_idIntegerNoSpecific location ID (use OR ottimate_group_id)
ottimate_group_idIntegerNoLocation group ID (use OR ottimate_location_id)
start_dateDateTimeNoDate when price becomes effective
end_dateDateTimeNoDate when price expires (null = no expiration)

Location-based prices can only be created and updated through the bulk upsert endpoint POST /catalog/entries/bulk.

  • Vendors API - Manage vendor relationships required for catalog entries
  • Dimensions API - Configure accounting dimensions for catalog items
  • Invoices API - Work with invoice data and matched catalog entries