# Search products

Operation ID: `searchAccountingProducts`

Group: Accounting › Products

[Open in the interactive reference](https://docs.api.lensing.ai/lensing/v1/endpoints/searchAccountingProducts)

`POST /accounting/products/search`

Read-only: A read that takes its filters in the body. Changes nothing, and ignores Idempotency-Key.

Searches products.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Api-Version` | header | string · v1 | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version `v1`. |

## Request body

Required, `application/json`: searchAccountingProductsInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `filters` | object | no | The filters to apply. A product must match every filter you send. Omit to return all products. |
| `filters.term` | string | no | Limits results to products whose name, code or description contains this text. The match is case-insensitive. |
| `filters.productCode` | string | no | Limits results to the product with this product code. The match is exact. |
| `filters.crmProductId` | string | no | Limits results to the product with this CRM identifier. The match is exact. |
| `filters.productStatus` | string | no | Limits results to products with this status. Accepted values: 'draft', 'available', 'unavailable', 'incomplete'. |
| `filters.productFamily` | string | no | Limits results to products of this family. Accepted values: 'software', 'services', 'physicalProducts'. |
| `filters.productType` | string | no | Limits results to products of this type. Accepted values: 'sub', 'termLicense', 'support', 'professionalServices', 'training', 'usage', 'billableTravelExpense', 'bundle', 'hardwareConsumables', 'billablePassThrough', 'merchandise', 'shipping'. |
| `filters.isInventory` | boolean | no | Limits results to products with this inventory-tracking flag. |
| `filters.effectiveStartDate` | object | no | Limits results by the date the product becomes available. Bounds are inclusive. |
| `filters.effectiveStartDate.start` | string | no | The inclusive lower bound. Use format YYYY-MM-DD. |
| `filters.effectiveStartDate.end` | string | no | The inclusive upper bound. Use format YYYY-MM-DD. |
| `filters.effectiveEndDate` | object | no | Limits results by the date the product is no longer available. Bounds are inclusive. A product with no end date matches any lower bound. |
| `filters.effectiveEndDate.start` | string | no | The inclusive lower bound. Use format YYYY-MM-DD. |
| `filters.effectiveEndDate.end` | string | no | The inclusive upper bound. Use format YYYY-MM-DD. |
| `filters.lastModifiedDate` | object | no | Limits results by the date and time the product last changed. Bounds are inclusive. |
| `filters.lastModifiedDate.start` | string | no | The inclusive lower bound, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
| `filters.lastModifiedDate.end` | string | no | The inclusive upper bound, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
| `filters.entityId` | string | no | Limits results to products visible to this legal entity: shared products and products assigned to it. See id on GET base/entities. An identifier that matches no entity returns an empty page, not an error. |
| `page` | object | no | The pagination controls. Omit for the first page. |
| `page.cursor` | string | no | The cursor from the previous response's pagination.nextCursor. Omit for the first page. |
| `page.size` | number | no | The number of products per page. Defaults to 50. A value above 200 is treated as 200, not rejected. |

```json
{
  "filters": {
    "term": "<term>",
    "productCode": "<productCode>",
    "crmProductId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "productStatus": "<productStatus>",
    "productFamily": "<productFamily>",
    "productType": "<productType>",
    "isInventory": true,
    "effectiveStartDate": {
      "start": "<start>",
      "end": "<end>"
    },
    "effectiveEndDate": {
      "start": "<start>",
      "end": "<end>"
    },
    "lastModifiedDate": {
      "start": "<start>",
      "end": "<end>"
    },
    "entityId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "page": {
    "cursor": "<cursor>",
    "size": 0
  }
}
```

## Response

`200` Success

Under `data` (searchAccountingProductsOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array<object> | yes | The products on this page. An empty array when nothing matches. |
| `items[].id` | string | yes | The unique identifier for the product. |
| `items[].productName` | string | yes | The product's display name. |
| `items[].productCode` | string | yes | The product's code, unique within the tenant. |
| `items[].productNumber` | string | no | The product number, assigned by the system and unique within the tenant. Absent while none has been assigned. |
| `items[].description` | string | no | A description of the product shown to customers. |
| `items[].internalDescription` | string | no | A description of the product for internal use, not shown to customers. |
| `items[].crmProductId` | string | no | The product's identifier in an external CRM system. |
| `items[].effectiveStartDate` | date | yes | The date the product becomes available. Format YYYY-MM-DD. |
| `items[].effectiveEndDate` | date | no | The date the product is no longer available. Format YYYY-MM-DD. Absent for a product with no end date. |
| `items[].productFamily` | string | no | The product family. Possible values: 'software', 'services', 'physicalProducts'. |
| `items[].productType` | string | no | The product type. Possible values: 'sub', 'termLicense', 'support', 'professionalServices', 'training', 'usage', 'billableTravelExpense', 'bundle', 'hardwareConsumables', 'billablePassThrough', 'merchandise', 'shipping'. |
| `items[].productStatus` | string | no | The product's availability status, computed by the system. Possible values: 'draft', 'available', 'unavailable', 'incomplete'. The status is derived from the product's lines, pricing, and effective dates and cannot be set directly. |
| `items[].isInventory` | boolean | no | Whether the product is tracked as inventory. |
| `items[].itemIds` | array<string> | no | The inventory items linked to this product. Used only when isInventory is true. Absent when the product has none. See id on GET inventory/items/:id. |
| `items[].createdDate` | date-time | no | The date and time the product record was created, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
| `items[].lastModifiedDate` | date-time | yes | The date and time the product record last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
| `items[].externalIdentifiers` | array<object> | no | External identifiers owned by other systems, at most one per fieldName. Absent when the product has none. |
| `items[].externalIdentifiers[].fieldName` | string | yes | The configured field name of the external identifier, not its display label. |
| `items[].externalIdentifiers[].value` | string | yes | The identifier's value in the source system. |
| `items[].externalIdentifiers[].externalUrl` | string | no | An absolute http or https link to the object in the source system. Absent when none is set. |
| `pagination` | object | yes | The pagination information for this page. |
| `pagination.nextCursor` | string | no | The cursor for the next page. Pass it as page.cursor. Absent on the last page. |
| `pagination.hasMore` | boolean | yes | True when more products remain beyond this page. |

```json
{
  "data": {
    "items": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "productName": "<productName>",
        "productCode": "<productCode>",
        "productNumber": "<productNumber>",
        "description": "<description>",
        "internalDescription": "<internalDescription>",
        "crmProductId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "effectiveStartDate": "2026-01-15",
        "effectiveEndDate": "2026-01-15",
        "productFamily": "<productFamily>",
        "productType": "<productType>",
        "productStatus": "<productStatus>",
        "isInventory": true,
        "itemIds": [
          "<itemIds>"
        ],
        "createdDate": "2026-01-15T09:30:00.000Z",
        "lastModifiedDate": "2026-01-15T09:30:00.000Z",
        "externalIdentifiers": [
          {
            "fieldName": "<fieldName>",
            "value": "<value>",
            "externalUrl": "<externalUrl>"
          }
        ]
      }
    ],
    "pagination": {
      "nextCursor": "<nextCursor>",
      "hasMore": true
    }
  },
  "diagnostics": [
    {
      "code": "<code>",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": "<details>"
    }
  ]
}
```

## Statuses

- `400` — Invalid request or business failure
- `401` — The request carries no valid access token.
- `403` — Not authorized
- `404` — Not found
- `429` — Too many requests from this client address. The response has no body and no `Retry-After` header.
- `500` — Internal server error
