> ## Documentation Index
> Fetch the complete documentation index at: https://learn.nexudus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Search Products

> Search and list Product records with filtering, sorting, and pagination.

A **Product** represents an item that can be sold to customers. Products can be sold via contracts (`ContractProduct` entity), added to bookings (`BookingProduct` entity), or purchased directly (`CoworkerProduct` entity).

Products support both one-off sales and recurring charges. Recurring charges can be set to daily, weekly, monthly, or yearly frequencies, or charged every time a contract is invoiced. For invoice-linked recurring charges, prefer using `ContractProduct` to associate the sale directly with a specific contract rather than relying on the customer's `MainContract`.

Use `AvailableAs` to control whether a product can be sold as a one-off purchase, a recurring charge, or both. The `SystemProductType` field categorises the product (e.g. day pass, credit bundle, booking product, stationery, or other).

Products can optionally track stock levels, be restricted to specific pricing plans (tariffs), and be limited to members or contacts only.

## Authentication

<Note>
  This endpoint requires OAuth2 authentication. Include a valid bearer token in the `Authorization` header.
  The authenticated user must be a full unrestricted administrator or have the **`Product-List`** role.
</Note>

## Enums

<Accordion title="eProductType — SystemProductType values">
  | Value | Name            |
  | ----- | --------------- |
  | 0     | None            |
  | 1     | DayPass         |
  | 2     | CreditBundle    |
  | 3     | Stationery      |
  | 4     | BookingFeature  |
  | 5     | BookingProducts |
  | 99    | Other           |
</Accordion>

<Accordion title="eRecurrentProductOptions — AvailableAs values">
  | Value | Name              |
  | ----- | ----------------- |
  | 0     | None              |
  | 1     | RecurrentOrOneOff |
  | 2     | OnlyRecurrent     |
  | 3     | OnlyOneOff        |
</Accordion>

## Query Parameters

### Pagination & Sorting

<ParamField query="page" type="integer" default="1">
  The page number to retrieve.
</ParamField>

<ParamField query="size" type="integer" default="25">
  The number of records per page.
</ParamField>

<ParamField query="orderBy" type="string">
  The property name to sort results by (e.g. `Name`, `CreatedOn`).
</ParamField>

<ParamField query="dir" type="integer">
  Sort direction. `0` for ascending, `1` for descending.
</ParamField>

### Filters

<ParamField query="Product_Business" type="integer">
  Filter by Business Id.
</ParamField>

<ParamField query="Product_Business_Name" type="string">
  Filter by business name.
</ParamField>

<ParamField query="Product_Name" type="string">
  Filter by product name.
</ParamField>

<ParamField query="Product_SystemProductType" type="integer">
  Filter by category of the product: DayPass, CreditBundle, Stationery, BookingFeature, BookingProducts, or Other.
</ParamField>

<ParamField query="Product_Description" type="string">
  Filter by product description.
</ParamField>

<ParamField query="Product_InvoiceLineDisplayAs" type="string">
  Filter by custom text shown on the invoice line instead of the product name.
</ParamField>

<ParamField query="Product_Sku" type="string">
  Filter by sKU code.
</ParamField>

<ParamField query="Product_Tags" type="string">
  Filter by tags.
</ParamField>

<ParamField query="Product_DisplayOrder" type="integer">
  Filter by display order.
</ParamField>

<ParamField query="Product_Price" type="number">
  Filter by product price.
</ParamField>

<ParamField query="Product_Visible" type="boolean">
  Filter by whether the product is visible to customers on the members portal and mobile app.
</ParamField>

<ParamField query="Product_SyncToSquare" type="boolean">
  Filter by sync to Square.
</ParamField>

<ParamField query="Product_Currency" type="integer">
  Filter by Currency Id.
</ParamField>

<ParamField query="Product_Currency_Code" type="string">
  Filter by currency code.
</ParamField>

<ParamField query="Product_TaxRate" type="integer">
  Filter by Tax Rate Id.
</ParamField>

<ParamField query="Product_ReducedTaxRate" type="integer">
  Filter by Reduced Tax Rate Id.
</ParamField>

<ParamField query="Product_ExemptTaxRate" type="integer">
  Filter by Exempt Tax Rate Id.
</ParamField>

<ParamField query="Product_FinancialAccount" type="integer">
  Filter by Financial Account Id.
</ParamField>

<ParamField query="Product_AvailableAs" type="integer">
  Filter by controls whether the product can be sold as a one-off purchase, a recurring charge, or both (RecurrentOrOneOff, OnlyRecurrent, OnlyOneOff).
</ParamField>

<ParamField query="Product_OnlyForContacts" type="boolean">
  Filter by restrict purchase to contacts (customers without an active contract).
</ParamField>

<ParamField query="Product_OnlyForMembers" type="boolean">
  Filter by restrict purchase to customers with an active contract (members).
</ParamField>

<ParamField query="Product_Archived" type="boolean">
  Filter by whether the product is archived. Archived products cannot be sold but existing charges remain active.
</ParamField>

<ParamField query="Product_Starred" type="boolean">
  Filter by mark the product as featured or highlighted.
</ParamField>

<ParamField query="Product_TrackStock" type="boolean">
  Filter by enable stock tracking for this product. When enabled, each sale reduces the stock count.
</ParamField>

<ParamField query="Product_AllowNegativeStock" type="boolean">
  Filter by allow sales to continue even when stock reaches zero.
</ParamField>

<ParamField query="Product_CurrentStock" type="integer">
  Filter by current stock level.
</ParamField>

<ParamField query="Product_StockAlertLevel" type="integer">
  Filter by stock level at which a low-stock alert is triggered.
</ParamField>

<ParamField query="Product_ApplyProRating" type="boolean">
  Filter by whether to pro-rate the price when the product is added or removed part-way through a billing period.
</ParamField>

<ParamField query="Product_ImageFileName" type="string">
  Filter by Image File Name.
</ParamField>

<ParamField query="Product_NewImageUrl" type="string">
  Filter by New Image Url.
</ParamField>

<ParamField query="Product_ClearImage" type="boolean">
  Filter by Clear Image File.
</ParamField>

<ParamField query="Product_InvoiceCoworker" type="boolean">
  Filter by whether to invoice the customer directly rather than their company or team.
</ParamField>

<ParamField query="Product_SyncToNexKiosk" type="boolean">
  Filter by sync to NexKiosk.
</ParamField>

<ParamField query="Product_CreateDeliveryWhenPurchased" type="boolean">
  Filter by automatically create a delivery record for the customer when this product is purchased.
</ParamField>

### Range Filters

<ParamField query="from_Product_DisplayOrder" type="integer">
  Filter by display order greater than or equal to this value.
</ParamField>

<ParamField query="to_Product_DisplayOrder" type="integer">
  Filter by display order less than or equal to this value.
</ParamField>

<ParamField query="from_Product_Price" type="number">
  Filter by product price greater than or equal to this value.
</ParamField>

<ParamField query="to_Product_Price" type="number">
  Filter by product price less than or equal to this value.
</ParamField>

<ParamField query="from_Product_CurrentStock" type="integer">
  Filter by current stock level greater than or equal to this value.
</ParamField>

<ParamField query="to_Product_CurrentStock" type="integer">
  Filter by current stock level less than or equal to this value.
</ParamField>

<ParamField query="from_Product_StockAlertLevel" type="integer">
  Filter by stock level at which a low-stock alert is triggered greater than or equal to this value.
</ParamField>

<ParamField query="to_Product_StockAlertLevel" type="integer">
  Filter by stock level at which a low-stock alert is triggered less than or equal to this value.
</ParamField>

<ParamField query="from_Product_CreatedOn" type="string">
  Filter records created on or after this date. Format: `YYYY-MM-DDTHH:mm`.
</ParamField>

<ParamField query="to_Product_CreatedOn" type="string">
  Filter records created on or before this date. Format: `YYYY-MM-DDTHH:mm`.
</ParamField>

<ParamField query="from_Product_UpdatedOn" type="string">
  Filter records updated on or after this date. Format: `YYYY-MM-DDTHH:mm`.
</ParamField>

<ParamField query="to_Product_UpdatedOn" type="string">
  Filter records updated on or before this date. Format: `YYYY-MM-DDTHH:mm`.
</ParamField>

## Code Examples

### Simple listing

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET \
    "https://spaces.nexudus.com/api/billing/products?page=1&size=15&orderBy=Name&dir=0" \
    -H "Authorization: Bearer YOUR_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://spaces.nexudus.com/api/billing/products?' + new URLSearchParams({
      page: 1,
      size: 15,
      orderBy: 'Name',
      dir: 1 // Ascending
    }),
    {
      headers: {
        'Authorization': 'Bearer YOUR_TOKEN'
      }
    }
  );

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://spaces.nexudus.com/api/billing/products',
      params={
          'page': 1,
          'size': 15,
          'orderBy': 'Name',
          'dir': 0 // Ascending
      },
      headers={
          'Authorization': 'Bearer YOUR_TOKEN'
      }
  )

  data = response.json()
  ```
</CodeGroup>

### Filtering by Name

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET \
    "https://spaces.nexudus.com/api/billing/products?Product_Name=example-value&orderBy=Name&dir=0" \
    -H "Authorization: Bearer YOUR_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://spaces.nexudus.com/api/billing/products?' + new URLSearchParams({
      Product_Name: 'example-value',
      orderBy: 'Name',
      dir: 1
    }),
    {
      headers: {
        'Authorization': 'Bearer YOUR_TOKEN'
      }
    }
  );

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://spaces.nexudus.com/api/billing/products',
      params={
          'Product_Name': 'example-value',
          'orderBy': 'Name',
          'dir': 0 // Ascending
      },
      headers={
          'Authorization': 'Bearer YOUR_TOKEN'
      }
  )

  data = response.json()
  ```
</CodeGroup>

### Range filters

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET \
    "https://spaces.nexudus.com/api/billing/products?from_Product_UpdatedOn=2025-01-01T00:00&to_Product_UpdatedOn=2025-12-31T23:59&orderBy=UpdatedOn&dir=0" \
    -H "Authorization: Bearer YOUR_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://spaces.nexudus.com/api/billing/products?' + new URLSearchParams({
      from_Product_UpdatedOn: '2025-01-01T00:00',
      to_Product_UpdatedOn: '2025-12-31T23:59',
      orderBy: 'UpdatedOn',
      dir: 1 // Descending
     }),
    {
      headers: {
        'Authorization': 'Bearer YOUR_TOKEN'
      }
    }
  );

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://spaces.nexudus.com/api/billing/products',
      params={
          'from_Product_UpdatedOn': '2025-01-01T00:00',
          'to_Product_UpdatedOn': '2025-12-31T23:59',
          'orderBy': 'UpdatedOn',
          'dir': 1 // Descending
      },
      headers={
          'Authorization': 'Bearer YOUR_TOKEN'
      }
  )

  data = response.json()
  ```
</CodeGroup>

## Response

### 200

<ResponseField name="Records" type="Product[]">
  The list of Product records matching the query. See the [Get one Product](/rest-api/billing/get-products-by-id) endpoint for the full list of properties returned for each record.
</ResponseField>

<Warning>
  **Partial records** — The listing endpoint returns a summary representation of each Product. The following fields are **not populated** in the `Records[]` response: `DisplayOrder`, `AvailableAs`, `OnlyForContacts`, `OnlyForMembers`, `InvoiceCoworker`.

  To get all fields, fetch the full record using the [Get one Product](/rest-api/billing/get-products-by-id) endpoint.

  **Important for updates:** When updating a record via `PUT`, always retrieve the full record with a `GET` request first, apply your changes to that complete data, and then send the updated record. Do not use data from a listing response as the base for a `PUT` request, as missing fields may be unintentionally cleared.
</Warning>

<ResponseField name="CurrentPage" type="integer">
  Current page number.
</ResponseField>

<ResponseField name="CurrentPageSize" type="integer">
  Number of records per page.
</ResponseField>

<ResponseField name="CurrentOrderField" type="string">
  The field used for sorting.
</ResponseField>

<ResponseField name="CurrentSortDirection" type="integer">
  The sort direction (`0` = ascending, `1` = descending).
</ResponseField>

<ResponseField name="FirstItem" type="integer">
  Index of the first item on the current page.
</ResponseField>

<ResponseField name="LastItem" type="integer">
  Index of the last item on the current page.
</ResponseField>

<ResponseField name="TotalItems" type="integer">
  Total number of matching records across all pages.
</ResponseField>

<ResponseField name="TotalPages" type="integer">
  Total number of pages.
</ResponseField>

<ResponseField name="HasNextPage" type="boolean">
  Whether there is a next page of results.
</ResponseField>

<ResponseField name="HasPreviousPage" type="boolean">
  Whether there is a previous page of results.
</ResponseField>

```json Example Response theme={null}
{
  "Records": [
    {
      "BusinessId": 0,
      "BusinessName": null,
      "Name": "",
      "SystemProductType": 0,
      "Description": "",
      "InvoiceLineDisplayAs": null,
      "Sku": null,
      "Tags": null,
      "Price": 0,
      "Visible": false,
      "SyncToSquare": false,
      "CurrencyId": 0,
      "CurrencyCode": null,
      "TaxRateId": null,
      "ReducedTaxRateId": null,
      "ExemptTaxRateId": null,
      "FinancialAccountId": null,
      "Tariffs": [],
      "Archived": false,
      "Starred": false,
      "TrackStock": false,
      "AllowNegativeStock": false,
      "CurrentStock": null,
      "StockAlertLevel": null,
      "ApplyProRating": false,
      "ImageFileName": null,
      "NewImageUrl": null,
      "ClearImageFile": null,
      "SyncToNexKiosk": false,
      "CreateDeliveryWhenPurchased": false,
      "Id": 87654321,
      "UpdatedOn": "2025-01-15T10:30:00Z",
      "CreatedOn": "2025-01-10T08:00:00Z",
      "UniqueId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "UpdatedBy": "admin@example.com",
      "IsNew": false,
      "SystemId": null,
      "ToStringText": "Product Example",
      "LocalizationDetails": null,
      "CustomFields": null
    }
  ],
  "CurrentPageSize": 15,
  "CurrentPage": 1,
  "CurrentOrderField": "Name",
  "CurrentSortDirection": 1,
  "FirstItem": 1,
  "HasNextPage": false,
  "HasPreviousPage": false,
  "LastItem": 1,
  "PageNumber": 1,
  "PageSize": 15,
  "TotalItems": 1,
  "TotalPages": 1
}
```
