Skip to main content

List Products

GET 

/api/v2/products

Get a paginated list of products using Spatie QueryBuilder.

Required scope: products:read

Grant this scope to your token under Settings → Developer → Personal Access Tokens.

Authentication: Requires Bearer token.

Supports both simple query filters (filter[field]=value) and advanced grouped filters (filter_groups tree). Default: shows non-archived products sorted by -created_at.

Allowed sorts: id, sku, name, type, barcode, mpn, hts_code, unit_cost, average_cost, supplier_price, weight, length, width, height, case_quantity, case_weight, daily_average_consumption, daily_average_consumption_net_returns, min_stock_level, total_quantity_sold, total_orders, archived_at, created_at, updated_at

Default pagination: 10 per page.

The response also includes unfiltered_total, the count of rows in the base scope before any user filters are applied — used by the frontend to show export totals.

Stock UoM filters (added 2026-05-30):

  • filter[stock_uom_id] — by uom_id (exact, comma-separated)
  • filter[stock_uom_code] — by UoM code (advanced text ops)
  • filter[stock_uom_name] — by UoM display name (advanced text ops)

The response includes inventory_non_sellable — physically-present stock in non-sellable bins. It is excluded from inventory_available but is part of On Hand (On Hand = Available + Allocated + On Hold + Non-Sellable).

Also supports hts_code (Harmonized Tariff Schedule code) for filtering (filter[hts_code]) and sorting.

Sparse fieldsets (included): Pass included a JSON array of response field names to receive only those fields. The server then loads only the data those fields need instead of the full product payload, which makes narrow lookups — resolving a barcode to a product, for example — markedly cheaper. id is always returned. Omitting the parameter returns the complete payload, unchanged.

Example: included=["id","sku","barcode","inventory_available"]

Request

Responses

OK

Response Headers
    Content-Type