openapi: 3.1.0
info:
title: API Reference accounts catalog API
version: 1.0.0
servers:
- url: https://api.ottimate.com/v1
description: Production
- url: https://sandbox-api.ottimate.com/v1
description: Sandbox
tags:
- name: catalog
paths:
/catalog/entries:
get:
operationId: get-catalog-entries
summary: List catalog entries
description: Returns a paginated list of catalog entries, filterable by company, vendor, and search term.
tags:
- catalog
parameters:
- name: ottimate_company_id
in: query
description: Filter entries by company ID (required)
required: true
schema:
type: integer
- name: erp_vendor_id
in: query
description: Filter entries by vendor name
required: false
schema:
type: string
- name: search
in: query
description: Search term based on item description or name
required: false
schema:
type: string
- name: page
in: query
description: 'Page number (default: 1)'
required: false
schema:
type: integer
- name: limit
in: query
description: 'Items per page (default: 50, max: 100)'
required: false
schema:
type: integer
- name: expand
in: query
description: 'Comma-separated list of fields to expand. Options: prices, allowances. When used, returns full CatalogEntryObject instead of CatalogEntryBasicObject.'
required: false
schema:
type: string
- name: sku
in: query
description: SKU code
required: false
schema:
type: string
- name: upc
in: query
description: UPC code
required: false
schema:
type: string
- name: buying_format
in: query
description: Buying format (e.g. 'CASE', 'EACH'). Pass 'null' to filter entries that have no buying format (NULL or empty).
required: false
schema:
type: string
- name: size
in: query
description: Pack size (e.g. '6 CT', '10 LB')
required: false
schema:
type: string
- name: uom
in: query
description: Unit of measure (e.g. 'CASE', 'EACH', 'LB')
required: false
schema:
type: string
- name: price
in: query
description: Price for the pack size
required: false
schema:
type: number
format: double
- name: unit_price
in: query
description: Price per individual unit within the pack
required: false
schema:
type: number
format: double
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
responses:
'200':
description: Successful response with paginated catalog entry list
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogEntryListResponse'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized - Authentication required or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
operationId: post-catalog-entries
summary: Create a catalog entry
description: Creates a new catalog entry or updates an existing one if catalog_unique_key matches.
tags:
- catalog
parameters:
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
- name: Idempotency-Key
in: header
description: 'Client-generated unique key (UUID/ULID recommended). JSON requests: the first 2xx response is cached for 24h and replayed on a same-key retry with a matching body; a different body returns 422. Non-JSON requests (e.g. file uploads): the key is single-use — any same-key retry returns 422 regardless of body. See [Idempotency](https://docs.ottimate.com/idempotency) for full details.'
required: false
schema:
type: string
responses:
'201':
description: Catalog entry created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogEntryObject'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized - Authentication required or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
description: ''
content:
application/json:
schema:
type: object
properties:
ottimate_company_id:
type: integer
description: The Ottimate company ID this catalog entry belongs to
erp_vendor_id:
type: string
description: ERP Vendor id from ERP/accounting system
item_name:
type: string
description: Item name for the catalog entry
description:
type: string
description: 'Deprecated: use item_name instead. This field will be removed in a future API version.'
original_description:
type: string
description: Original item description from source system
sku:
type: string
description: SKU code
upc:
type: string
description: UPC code
buying_format:
type:
- string
- 'null'
description: Buying format distinguishing multiple purchasing formats for the same item (e.g., 'CASE', 'EACH'). Used as part of the composite unique key for integrations that differentiate catalog entries by buying format. Optional — null or omitted for integrations that do not use buying format.
size:
type: string
description: Pack size (e.g., '6 CT', '10 LB')
uom:
type: string
description: Unit of measure (e.g., 'CASE', 'EACH', 'LB')
price:
type: number
format: double
description: Price for the pack size
unit_price:
type: number
format: double
description: Price per individual unit within the pack
is_split_case:
type: boolean
description: Whether items can be purchased in split case quantities
authorized_vendor:
type: boolean
description: Whether the vendor is authorized for this item
catalog_unique_key:
type: string
description: 'Unique key used to match existing entries for upsert. If omitted, the API auto-generates a key from erp_vendor_id, sku, size, and description. Key normalization: the value is derived from the entry''s core identifying fields — the key returned in the response may differ from what you submitted. Always store and reuse the returned catalog_unique_key. Key regeneration: modifying erp_vendor_id, sku, size, or description will generate a new key that no longer matches the existing entry — the API will create a new entry instead of updating the old one, leaving the previous entry as an orphan. To avoid duplicates, store the latest catalog_unique_key from the response and include it in subsequent requests.'
last_purchased_price:
type: number
format: double
description: Last purchased price for this item
reference_id:
type: string
description: External reference ID for tracking
dimensions:
description: 'POS dimensions for this catalog entry — these are point-of-sale system dimensions, separate from ERP/accounting dimensions and not validated against your accounting configuration. Input Structure: a list of objects, each with one dimension-type key (value = dimension name) plus an optional ''code'', e.g. [{"DEPARTMENT": "Marketing", "code": "321654"}]. Omit the field or pass null to leave dimensions unchanged.'
properties:
$ref: '#/components/schemas/CatalogEntriesPostRequestBodyContentApplicationJsonSchema'
description: Additional custom properties as key-value pairs
prices:
type:
- array
- 'null'
items:
$ref: '#/components/schemas/CatalogEntriesPostRequestBodyContentApplicationJsonSchemaPricesItems'
description: Prices to create with this catalog entry. Must be present in the request — pass null to explicitly indicate no prices. Omitting this field is deprecated and will return a warning in the response.
allowances:
type:
- array
- 'null'
items:
$ref: '#/components/schemas/CatalogEntriesPostRequestBodyContentApplicationJsonSchemaAllowancesItems'
description: Allowances to create with this catalog entry. Must be present in the request — pass null to explicitly indicate no allowances. Omitting this field is deprecated and will return a warning in the response.
required:
- ottimate_company_id
- erp_vendor_id
- item_name
- prices
- allowances
/catalog/entries/{id}:
get:
operationId: get-catalog-entries-id
summary: Retrieve a catalog entry
description: Returns detailed information for a single catalog entry.
tags:
- catalog
parameters:
- name: id
in: path
description: The unique ID of the catalog entry
required: true
schema:
type: string
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
responses:
'200':
description: Successful response with catalog entry details
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogEntryObject'
'404':
description: Not found - Resource does not exist
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
patch:
operationId: patch-catalog-entries-id
summary: Update a catalog entry
description: Updates an existing catalog entry by ID.
tags:
- catalog
parameters:
- name: id
in: path
description: The unique ID of the catalog entry
required: true
schema:
type: string
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
responses:
'200':
description: Catalog entry updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogEntryObject'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden - Access denied or insufficient permissions
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not found - Resource does not exist
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
description: ''
content:
application/json:
schema:
type: object
properties:
erp_vendor_id:
type: string
description: ERP Vendor id from ERP/accounting system
item_name:
type: string
description: Item name for the catalog entry
description:
type: string
description: 'Deprecated: use item_name instead. This field will be removed in a future API version.'
original_description:
type: string
description: Original item description
sku:
type: string
description: SKU code
upc:
type: string
description: UPC code
buying_format:
type:
- string
- 'null'
description: Buying format distinguishing multiple purchasing formats for the same item (e.g., 'CASE', 'EACH'). Used as part of the composite unique key for integrations that differentiate catalog entries by buying format. Optional — null or omitted for integrations that do not use buying format.
size:
type: string
description: Pack size
uom:
type: string
description: Unit of measure
price:
type: number
format: double
description: Price
unit_price:
type: number
format: double
description: Unit price
is_split_case:
type: boolean
description: Split case indicator
authorized_vendor:
type: boolean
description: Whether vendor is authorized
erp_vendor_name:
type:
- string
- 'null'
description: 'Optional. Human-readable vendor name attached to erp_vendor_id, sourced from the originating system. Note: reads return the resolved vendor name for the entry, which may come from upstream ERP/sync sources rather than this field. Omit to leave unchanged; pass empty string to clear.'
dimensions:
description: 'POS dimensions for this catalog entry — these are point-of-sale system dimensions, separate from ERP/accounting dimensions and not validated against your accounting configuration. Input Structure: a list of objects, each with one dimension-type key (value = dimension name) plus an optional ''code'', e.g. [{"DEPARTMENT": "Marketing", "code": "321654"}]. Omit the field or pass null to leave dimensions unchanged.'
properties:
$ref: '#/components/schemas/CatalogEntriesIdPatchRequestBodyContentApplicationJsonSchema'
description: Additional properties
/catalog/allowances:
get:
operationId: get-catalog-allowances
summary: List catalog allowances
description: Returns a paginated list of catalog allowances, filterable by company, catalog entry, location, and effective date.
tags:
- catalog
parameters:
- name: ottimate_company_id
in: query
description: Filter allowances by company ID (required)
required: true
schema:
type: integer
- name: catalog_entry_id
in: query
description: Filter by catalog entry ID
required: false
schema:
type: string
- name: ottimate_location_id
in: query
description: Filter by location ID
required: false
schema:
type: integer
- name: effective_date
in: query
description: Filter allowances valid on this date (YYYY-MM-DD)
required: false
schema:
type: string
format: date
- name: page
in: query
description: Page number (default 1)
required: false
schema:
type: integer
- name: limit
in: query
description: Number of results per page (default 20)
required: false
schema:
type: integer
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
responses:
'200':
description: Successful response with paginated allowance list
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogAllowanceListResponse'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
operationId: post-catalog-allowances
summary: Create a catalog allowance
description: Creates a new catalog allowance for a catalog entry.
tags:
- catalog
parameters:
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
- name: Idempotency-Key
in: header
description: 'Client-generated unique key (UUID/ULID recommended). JSON requests: the first 2xx response is cached for 24h and replayed on a same-key retry with a matching body; a different body returns 422. Non-JSON requests (e.g. file uploads): the key is single-use — any same-key retry returns 422 regardless of body. See [Idempotency](https://docs.ottimate.com/idempotency) for full details.'
required: false
schema:
type: string
responses:
'201':
description: Catalog allowance created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogAllowanceObject'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized - Authentication required or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
description: ''
content:
application/json:
schema:
type: object
properties:
ottimate_company_id:
type: integer
description: The Ottimate company ID this allowance belongs to
catalog_entry_id:
type: integer
description: The ID of the catalog entry this allowance applies to
allowance_type:
$ref: '#/components/schemas/CatalogAllowancesPostRequestBodyContentApplicationJsonSchemaAllowanceType'
description: 'Type of allowance (default: ''allowance'')'
amount:
type: number
format: double
description: Allowance amount for the pack size
unit_allowance:
type: number
format: double
description: 'Allowance amount per individual unit (default: 0)'
target:
$ref: '#/components/schemas/CatalogAllowancesPostRequestBodyContentApplicationJsonSchemaTarget'
description: 'Allowance target: company (default), location_group, or location'
ottimate_location_id:
type: integer
description: Location ID (required when target is location)
ottimate_group_id:
type: integer
description: Location group ID (required when target is 15/location_group)
start_date:
type: string
format: date-time
description: Allowance effective start date (ISO 8601)
end_date:
type: string
format: date-time
description: Allowance effective end date (ISO 8601, optional)
reference_id:
type: string
description: Unique reference ID for upsert operations
required:
- ottimate_company_id
- catalog_entry_id
- amount
- start_date
/catalog/allowances/{id}:
patch:
operationId: patch-catalog-allowances-id
summary: Update a catalog allowance
description: Updates an existing catalog allowance by ID.
tags:
- catalog
parameters:
- name: id
in: path
description: The unique ID of the catalog allowance
required: true
schema:
type: string
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
responses:
'200':
description: Catalog allowance updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogAllowanceObject'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden - Access denied or insufficient permissions
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not found - Resource does not exist
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
description: ''
content:
application/json:
schema:
type: object
properties:
allowance_type:
$ref: '#/components/schemas/CatalogAllowancesIdPatchRequestBodyContentApplicationJsonSchemaAllowanceType'
description: Type of allowance
amount:
type: number
format: double
description: Allowance amount
unit_allowance:
type: number
format: double
description: Unit allowance amount
target:
$ref: '#/components/schemas/CatalogAllowancesIdPatchRequestBodyContentApplicationJsonSchemaTarget'
description: 'Allowance target: company, location_group, or location'
ottimate_location_id:
type: integer
description: Location ID
ottimate_group_id:
type: integer
description: Restaurant group ID
start_date:
type: string
format: date-time
description: Start date
end_date:
type: string
format: date-time
description: End date
/catalog/variances:
get:
operationId: get-catalog-variances
summary: List catalog variances
description: Returns catalog entries with price variance information from invoice items. By default, returns all items that had purchases in the specified period, including items with zero variance. Use variance_only=true to return only entries with non-zero variance. Use expand=invoice_items to include all invoice items inline (otherwise only the most recent invoice item is returned).
tags:
- catalog
parameters:
- name: ottimate_company_id
in: query
description: Filter by company ID (required)
required: true
schema:
type: integer
- name: variance_only
in: query
description: 'If true, returns only entries with non-zero variance. Default: false (returns all items including zero variance)'
required: false
schema:
type: boolean
- name: expand
in: query
description: Comma-separated list of fields to expand. Supports 'invoice_items' to include all invoice items for each entry.
required: false
schema:
type: string
- name: invoice_start_date
in: query
description: Start of date range (YYYY-MM-DD)
required: false
schema:
type: string
format: date
- name: invoice_end_date
in: query
description: End of date range (YYYY-MM-DD)
required: false
schema:
type: string
format: date
- name: erp_vendor_ids
in: query
description: Comma-separated ERP vendor IDs (accounting vendor IDs) to filter variances by vendor.
required: false
schema:
type: string
- name: ottimate_location_ids
in: query
description: Comma-separated location IDs
required: false
schema:
type: string
- name: exception_type
in: query
description: Filter by variance type
required: false
schema:
$ref: '#/components/schemas/CatalogVariancesGetParametersExceptionType'
- name: page
in: query
description: Page number for pagination
required: false
schema:
type: integer
- name: limit
in: query
description: Number of items per page
required: false
schema:
type: integer
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
responses:
'200':
description: Successful response with paginated variance list
content:
application/json:
schema:
$ref: '#/components/schemas/VarianceListResponse'
'400':
description: Bad request - Invalid parameters or request format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/catalog/entries/bulk:
post:
operationId: post-catalog-entries-bulk
summary: Bulk create/update catalog entries (async)
description: 'Creates or updates multiple catalog entries asynchronously. Returns 202 with batch tracking info. Maximum 1000 entries per request. Poll GET /batch/{id}/progress for status.
**Deprecation notice:** The previous synchronous bulk API has been deprecated. This async endpoint is the recommended behavior going forward — it avoids timeouts on large batches and provides progress tracking via the batch polling API.'
tags:
- catalog
parameters:
- name: Authorization
in: header
description: OAuth2 authentication flows. Auth server URLs will vary by environment
required: true
schema:
type: string
- name: X-Api-Key
in: header
description: API key for authentication
required: true
schema:
type: string
- name: X-API-Version
in: header
description: 'API version to use (optional, defaults to latest). Supported values: 1.0.0, 1.1.0.'
required: false
schema:
type: string
- name: Idempotency-Key
in: header
description: 'Client-generated unique key (UUID/ULID recommended). JSON requests: the first 2xx response is cached for 24h and replayed on a same-key retry with a matching body; a different body returns 422. Non-JSON requests (e.g. file uploads): the key is single-use — any same-key retry returns 422 regardless of body. See [Idempotency](https://docs.ottimate.com/idempotency) for full details.'
required: false
schema:
type: string
responses:
'202':
description: Asynchronous processing started. Poll batch_url for status.
content:
application/jso
# --- truncated at 32 KB (92 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/plateiq/refs/heads/main/openapi/plateiq-catalog-api-openapi.yml