Get products
Returns a paginated list of products, oldest first (ascending by creation
time). Soft-deleted products are excluded unless you opt into them with the
deleted filter. The response is a {data, next_page} envelope; follow
next_page (null on the last page) to walk every page.
This endpoint is eventually consistent: a create or update made through the API can take up to about one second to appear or change here, so a product you just wrote may briefly be missing or stale in the list.
Required permission: products_permissions_view. Results are additionally
limited to the products the authenticated user can see under their team
restrictions, so two API keys at the same company can return different sets.
BearerAuthorizationBearer <token>API token generated in Distru (Settings → Distru API). Send it on every request as Authorization: Bearer YOUR_API_TOKEN.
name?stringCase-insensitive substring match on the product's name. Omit to match products of any name.
sku?stringCase-insensitive substring match on the product's SKU. Omit to match products of any SKU.
upc?stringCase-insensitive substring match on the product's UPC. Omit to match products of any UPC.
names[]?array<string>Restrict to products whose name exactly matches (case-insensitive) any value in the list. Repeat the bracketed key once per value.
skus[]?array<string>Restrict to products whose SKU exactly matches (case-insensitive) any value in the list. Repeat the bracketed key once per value.
upcs[]?array<string>Restrict to products whose UPC exactly matches (case-insensitive) any value in the list. Repeat the bracketed key once per value.
inserted_datetime?stringFilter by product creation time. A comma-separated after,before pair of ISO8601 UTC datetimes, both bounds inclusive. Leave either side empty to make that bound open-ended: 2022-07-10T00:00:00Z, returns products created at or after that instant, ,2022-07-10T00:00:00Z returns those created at or before it.
deleted?stringWhether to include soft-deleted products. no (the default) returns only non-deleted products, only returns only soft-deleted ones, include returns both. Note these values are lower-case, unlike response enums.
"no""no""include""only"ids[]?array<string>Restrict the result to specific products by ID (the same ID returned as each product's id). Repeat the bracketed key once per ID. Unknown IDs simply match nothing; an empty list is treated as no filter.
category_ids[]?array<string>Restrict to products in any of these categories (the same ID returned as each product's category.id). Repeat the bracketed key once per ID. IDs that don't resolve match nothing.
subcategory_ids[]?array<string>Restrict to products in any of these subcategories (the same ID returned as each product's subcategory.id). Repeat the bracketed key once per ID.
product_group_ids[]?array<string>Restrict to products in any of these groups (the same ID returned as each product's product_group.id). Repeat the bracketed key once per ID.
brand_ids[]?array<string>Restrict to products with any of these brands (the same ID returned as each product's brand.id). Repeat the bracketed key once per ID.
strain_ids[]?array<string>Restrict to products with any of these strains (the same ID returned as each product's strain.id). Repeat the bracketed key once per ID.
tag_ids[]?array<string>Restrict to products carrying any of these tags (the same ID returned in each product's tags[].id). Repeat the bracketed key once per ID.
vendor_ids[]?array<string>Restrict to products supplied by any of these vendors (the same ID returned as each product's vendor.id). This is the company-relationship ID, not the raw company ID. Repeat the bracketed key once per ID.
owner_ids[]?array<string>Restrict to products owned by any of these users (the same ID returned as each product's owner.id). Repeat the bracketed key once per ID.
unit_type_ids[]?array<string>Restrict to products with any of these unit types (the same ID returned as each product's unit_type.id). Repeat the bracketed key once per ID.
strain_types[]?array<>Restrict to products whose strain is of any of these types. Repeat the bracketed key once per value. SCREAMING_CASE.
leaflink_product_ids[]?array<integer>Restrict to products linked to any of these LeafLink product IDs (the integer leaflink_product_id returned on each product). Repeat the bracketed key once per ID.
inventory_tracking_method?stringRestrict to products with this inventory tracking method (the same value returned as each product's inventory_tracking_method). SCREAMING_CASE.
"PACKAGE""BATCH""PRODUCT"is_active?booleanRestrict to active (true) or inactive (false) products. Omit to match products regardless of active state.
is_featured?booleanRestrict to featured (true) or non-featured (false) products. Omit to match products regardless of featured state.
has_quantity_active?booleanRestrict to products that currently hold active inventory quantity (true) or none (false). Omit to match products regardless of active quantity.
page?stringPage selector. Page size is fixed by the server; paginate by following the next_page URL in each response rather than building page selectors yourself — it is null on the last page. next_page uses page[after]=<cursor>, an opaque token marking where the next page resumes; pass it back exactly as given, and only to the endpoint that issued it. This is seek-based, so every page stays fast no matter how deep you page.
updated_datetime?stringFilter by the time a product was last modified. Same after,before comma-separated ISO8601 UTC range format as inserted_datetime, both bounds inclusive, either side optional.
include_bill_of_materials?booleanWhen true, each product carries its bill_of_materials object (or null if it has none). Defaults to false, in which case bill_of_materials is omitted entirely to keep the list light.
falseinclude_packages_with_active_quantity_by_location?booleanWhen true, each product carries packages_with_active_quantity_by_location — its packages that hold active quantity, grouped by location (empty for products that are not package-tracked). Defaults to false, in which case the field is omitted. Because this runs extra per-product queries, setting it (or include_batches_with_active_quantity_by_location) shrinks the page size to 50.
falseinclude_batches_with_active_quantity_by_location?booleanWhen true, each product carries batches_with_active_quantity_by_location — its batches that hold active quantity, grouped by location, each batch carrying its active quantity at that location (empty for products that are not batch-tracked). Defaults to false, in which case the field is omitted. Because this runs extra per-product queries, setting it (or include_packages_with_active_quantity_by_location) shrinks the page size to 50.
falsecustom_data?Filter by custom field values, as custom_data[{id}]=value where {id} is a custom field's numeric id. Repeat with different ids to filter on several fields at once; a record must match every one (AND). Matching is case-sensitive exact against the value stored on the record. The id must be a filterable custom field defined on this entity — use GET /public/v1/custom-fields?parent_object=product to list the ids, their types, and which are filterable. A non-numeric id, an id not defined on this entity, or an id that isn't filterable returns a 400.
A list of products
*/*- response
A collection of Products
data?array<>Products
next_page?stringURL for the next page of results; null when there is no next page
curl -X GET 'https://app.distru.com/public/v1/products'{ "data": [ { "brand": { "id": "00000000-0000-0000-0000-000000000360", "name": "Company 2056", "updated_datetime": "2030-11-01T00:00:00.000000Z" }, "category": { "id": "00000000-0000-0000-0000-00000000020a", "name": "Some category 519", "official_product_category_id": "OTHER" }, "creator": { "banned": false, "deleted_at": null, "email": "[email protected]", "full_name": "FirstName6332 LastName6333", "id": "00000000-0000-0000-0000-000000000c42", "inserted_datetime": "2026-10-13T15:03:32.911562Z", "role": { "id": "00000000-0000-0000-0000-000000000cb1", "name": "Admin 3248" }, "updated_datetime": "2026-10-13T15:03:32.911562Z" }, "custom_data": [ { "id": 78, "name": "Custom Field 52", "value": "Custom Field Value 1" } ], "deleted_at": null, "description": "test", "description_markdown": "# test", "external_name": "External Name", "gross_weight": null, "gross_weight_unit_type": null, "id": "aed43549-55eb-4108-b0b4-d64ad8ce8735", "images": [ { "id": "00000000-0000-0000-0000-00000000001b", "name": "Image Name 232", "rank": 0, "url": "https://google.com/original-21.jpg" }, { "id": "00000000-0000-0000-0000-00000000001a", "name": "Image Name 230", "rank": 1, "url": "https://google.com/original-20.jpg" } ], "inserted_datetime": "2026-10-13T15:03:32.918205Z", "inventory_tracking_method": "BATCH", "is_active": true, "is_featured": true, "leaflink_product_id": 555, "menu_visibility": "INCLUDE_IN_ALL", "menus": [ { "id": "00000000-0000-0000-0000-000000000047", "menu_id": "00000000-0000-0000-0000-000000000047", "menu_name": "Menu 1", "name": "Menu 1" } ], "msrp": null, "name": "Product 1332", "owner": { "banned": false, "deleted_at": null, "email": "[email protected]", "full_name": "FirstName6332 LastName6333", "id": "00000000-0000-0000-0000-000000000c42", "inserted_datetime": "2026-10-13T15:03:32.911562Z", "role": { "id": "00000000-0000-0000-0000-000000000cb1", "name": "Admin 3248" }, "updated_datetime": "2026-10-13T15:03:32.911562Z" }, "product_group": { "id": "00000000-0000-0000-0000-0000000001e1", "name": "Product Group 477" }, "quantity_active": "0", "quantity_active_by_location": [], "quantity_available": "0", "quantity_available_threshold_max": "50", "quantity_available_threshold_min": "5", "quantity_reserved": "0", "sku": "sku 1333", "strain": { "id": "00000000-0000-0000-0000-000000000042", "name": "Strain 59", "strain_type": "INDICA" }, "subcategory": { "id": "00000000-0000-0000-0000-0000000001e6", "name": "Some subcategory 483" }, "tags": [ { "id": "00000000-0000-0000-0000-00000000002c", "name": "Tag 1" } ], "tasks": [], "total_cannabinoid_unit": "PERCENT", "total_cbd": "3", "total_thc": "12", "treez_wholesale_price": "12.34", "unit_cost": null, "unit_net_weight": "20", "unit_net_weight_serving_size_unit_type": { "id": "00000000-0000-0000-0000-00000000643f", "name": "Ounce" }, "unit_price": "1", "unit_serving_size": "10", "unit_type": { "id": "00000000-0000-0000-0000-00000000643d", "name": "Gram" }, "units_per_case": null, "upc": "036000291452", "updated_datetime": "2023-11-01T00:00:00.000000Z", "vendor": { "id": "00000000-0000-0000-0000-000000000364", "name": "Company 2061", "updated_datetime": "2030-11-03T00:00:00.000000Z" }, "wholesale_unit_price": 90.5 }, { "brand": { "id": "00000000-0000-0000-0000-000000000363", "name": "Company 2058", "updated_datetime": "2030-11-02T00:00:00.000000Z" }, "category": { "id": "00000000-0000-0000-0000-00000000020d", "name": "Some category 522", "official_product_category_id": "OTHER" }, "creator": null, "custom_data": [ { "id": 78, "name": "Custom Field 52", "value": null } ], "deleted_at": null, "description": null, "description_markdown": null, "external_name": null, "gross_weight": null, "gross_weight_unit_type": null, "id": "0505750d-63fc-4cc4-8590-42a52116b8b7", "images": [], "inserted_datetime": "2026-10-13T15:03:32.949233Z", "inventory_tracking_method": "PACKAGE", "is_active": false, "is_featured": false, "leaflink_product_id": null, "menu_visibility": "DO_NOT_INCLUDE", "menus": [], "msrp": "100", "name": "Product 1344", "owner": { "banned": false, "deleted_at": null, "email": "[email protected]", "full_name": "FirstName6332 LastName6333", "id": "00000000-0000-0000-0000-000000000c42", "inserted_datetime": "2026-10-13T15:03:32.911562Z", "role": { "id": "00000000-0000-0000-0000-000000000cb1", "name": "Admin 3248" }, "updated_datetime": "2026-10-13T15:03:32.911562Z" }, "product_group": { "id": "00000000-0000-0000-0000-0000000001e5", "name": "Product Group 481" }, "quantity_active": "0", "quantity_active_by_location": [], "quantity_available": "0", "quantity_available_threshold_max": null, "quantity_available_threshold_min": null, "quantity_reserved": "0", "sku": "sku 1345", "strain": null, "subcategory": { "id": "00000000-0000-0000-0000-0000000001ea", "name": "Some subcategory 487" }, "tags": [], "tasks": [], "total_cannabinoid_unit": null, "total_cbd": null, "total_thc": null, "treez_wholesale_price": null, "unit_cost": null, "unit_net_weight": null, "unit_net_weight_serving_size_unit_type": null, "unit_price": "1", "unit_serving_size": null, "unit_type": { "id": "00000000-0000-0000-0000-00000000643b", "name": "Pound" }, "units_per_case": null, "upc": null, "updated_datetime": "2023-11-02T00:00:00.000000Z", "vendor": { "id": "00000000-0000-0000-0000-000000000368", "name": "Company 2066", "updated_datetime": "2030-11-04T00:00:00.000000Z" }, "wholesale_unit_price": null } ], "next_page": null}