# Search purchase requests

Operation ID: `searchPurchaseRequest`

Group: Accounting › Purchase Requests

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

`POST /accounting/purchase-requests/search`

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

Searches purchase requests. Each match is the full purchase request with its lines. The vendorId, vendorName, entityId, entityName, and departmentId filters are available here and not on GET accounting/purchase-requests.

## 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`: searchPurchaseRequestInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `filters` | object | no | The filters to apply. A purchase request must match every filter you send. Omit to return all purchase requests. Example: `{"status":"pendingApproval"}`. |
| `filters.id` | string | no | Limits results to the purchase request with this id. GET accounting/purchase-requests/:id does the same more cheaply. |
| `filters.purchaseRequestNumber` | string | no | Limits results to the request with this number, for example 'PR-1'. The match is exact. It is unique, so this returns at most one. |
| `filters.status` | string | no | Limits results to requests in this state. Accepted values: 'pendingApproval', 'approved', 'rejected', 'closed'. Any other value matches no request. |
| `filters.currency` | string | no | Limits results to requests denominated in this currency. Format ISO 4217, for example 'USD'. |
| `filters.paymentTerms` | string | no | Limits results to requests with this payment-terms key, for example 'net30'. The match is exact. |
| `filters.externalId` | string | no | Limits results to requests with this external identifier. The match is exact. It is not unique, so this can return several requests. |
| `filters.vendorId` | string | no | Limits results to requests directed at this vendor. See id on GET accounting/vendors/:id. An id that matches no vendor returns an empty page, not an error. |
| `filters.entityId` | string | no | Limits results to requests of this legal entity. See id on GET base/entities. An id that matches no entity returns an empty page, not an error. |
| `filters.departmentId` | string | no | Limits results to requests raised by this department. See id on GET people/departments/:id. An id that matches no department returns an empty page, not an error. |
| `filters.vendorName` | string | no | Limits results to requests whose vendor has this name. The match is exact and case-sensitive. Use vendorId when you already have the id. |
| `filters.entityName` | string | no | Limits results to requests whose legal entity has this name. The match is exact and case-sensitive. |
| `page` | object | no | Pagination controls. Omit for the first page. Example: `{"size":50}`. |
| `page.cursor` | string | no | The cursor from the previous response's pagination.nextCursor. Omit on the first request. |
| `page.size` | number | no | The number of purchase requests per page. Defaults to 50, capped at 200. The server may return fewer, never more. |

```json
{
  "filters": {
    "status": "pendingApproval"
  },
  "page": {
    "size": 50
  }
}
```

## Response

`200` Success

Under `data` (searchPurchaseRequestOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array<object> | yes | The purchase requests on this page, most recently created first. An empty array when nothing matches. |
| `items[].id` | string | yes | The unique identifier for the purchase request. |
| `items[].purchaseRequestNumber` | string | no | The purchase request number, for example 'PR-1', unique across purchase requests. Absent until one has been assigned. |
| `items[].description` | string | no | A description of what is being requested. It is shown to the vendor. |
| `items[].internalDescription` | string | no | Internal notes on the request, not shown to the vendor. |
| `items[].externalMemo` | string | no | A memo intended for the vendor. |
| `items[].status` | string | no | The lifecycle and approval state, in one field. Possible values: 'pendingApproval', 'approved', 'rejected', 'closed'. This resource has no separate approvalStatus. |
| `items[].currency` | string | no | The currency the request is denominated in. Format ISO 4217, for example 'USD'. Governs totalAmount and every line amount. |
| `items[].totalAmount` | decimal | no | The total requested amount, the sum of the line totals, in the request currency. |
| `items[].startDate` | date | no | The first day of the period the request covers. Format YYYY-MM-DD. |
| `items[].endDate` | date | no | The last day of the period the request covers. Format YYYY-MM-DD. |
| `items[].needByDate` | date | no | The date the goods or services are needed by. Format YYYY-MM-DD. |
| `items[].paymentTerms` | string | no | The payment-terms key requested for the resulting order, for example 'net30'. |
| `items[].externalId` | string | no | The identifier this request has in the upstream system that produced it. It is not unique. |
| `items[].vendorId` | string | no | The vendor this request is directed at. See id on GET accounting/vendors/:id. Absent when no vendor has been chosen yet. |
| `items[].vendorName` | string | no | The name of the vendor this request is directed at. |
| `items[].entityId` | string | no | The legal entity this request belongs to. See id on GET base/entities. |
| `items[].entityName` | string | no | The name of the legal entity this request belongs to. |
| `items[].departmentId` | string | no | The department raising the request. See id on GET people/departments/:id. |
| `items[].departmentName` | string | no | The name of the department raising the request. |
| `items[].lastModifiedDate` | date-time | yes | The date and time the purchase request last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
| `items[].lines` | array<object> | no | The request line items, in their order on the request. An empty array when the request has none. |
| `items[].lines[].id` | string | yes | The unique identifier for the line item. |
| `items[].lines[].lineNumber` | string | no | The line number, for example 'PRL-1'. Unique across purchase request lines. |
| `items[].lines[].description` | string | no | A description of the line item. |
| `items[].lines[].isItem` | boolean | no | Whether the line references an inventory item. True for an item line, false for a free-text expense line. It is the item-versus-expense discriminator. There is no itemType field on this resource. |
| `items[].lines[].quantity` | decimal | no | The quantity requested, as a decimal. |
| `items[].lines[].price` | decimal | no | The unit price, in the request currency. Set on item lines. On expense lines the amount is on editableAmount instead. |
| `items[].lines[].editableAmount` | decimal | no | The directly entered line amount, in the request currency. Used on expense lines, where there is no unit price to multiply. |
| `items[].lines[].total` | decimal | no | The line total, in the request currency. price times quantity on an item line, editableAmount on an expense line. |
| `items[].lines[].currency` | string | no | The currency of the line. Format ISO 4217, for example 'USD'. Always the request currency, on each line so the line is self-describing. |
| `items[].lines[].status` | string | no | The delivery state of the line. Possible values: 'undelivered', 'delivering', 'delivered'. It is a delivery status, not an approval status. |
| `items[].lines[].priority` | string | no | The requested priority of the line. Possible values: 'high', 'medium', 'low'. |
| `items[].lines[].needByDate` | date | no | The date this line is needed by, when it differs from the header. Format YYYY-MM-DD. |
| `items[].lines[].deliveryDate` | date | no | The date this line was delivered. Format YYYY-MM-DD. |
| `items[].lines[].estimatedDeliveryDate` | date | no | The expected delivery date for this line. Format YYYY-MM-DD. |
| `items[].lines[].startDate` | date | no | The first day of the period this line covers. Format YYYY-MM-DD. |
| `items[].lines[].endDate` | date | no | The last day of the period this line covers. Format YYYY-MM-DD. |
| `items[].lines[].unitOfMeasure` | string | no | The name of the unit of measure for the quantity. |
| `items[].lines[].unitOfMeasureId` | string | no | The unit of measure for the quantity. See id on GET inventory/unit-of-measures/:id. |
| `items[].lines[].itemId` | string | no | The item this line orders. See id on GET inventory/items/:id. Present only on an item line. |
| `items[].lines[].departmentId` | string | no | The department this line is charged to. See id on GET people/departments/:id. |
| `pagination` | object | yes | The pagination cursor 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 | Whether more matches remain beyond this page. |

```json
{
  "data": {
    "items": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "purchaseRequestNumber": "<purchaseRequestNumber>",
        "description": "<description>",
        "internalDescription": "<internalDescription>",
        "externalMemo": "<externalMemo>",
        "status": "<status>",
        "currency": "<currency>",
        "totalAmount": "19.99",
        "startDate": "2026-01-15",
        "endDate": "2026-01-15",
        "needByDate": "2026-01-15",
        "paymentTerms": "<paymentTerms>",
        "externalId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "vendorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "vendorName": "<vendorName>",
        "entityId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "entityName": "<entityName>",
        "departmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "departmentName": "<departmentName>",
        "lastModifiedDate": "2026-01-15T09:30:00.000Z",
        "lines": [
          {
            "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
            "lineNumber": "<lineNumber>",
            "description": "<description>",
            "isItem": true,
            "quantity": "19.99",
            "price": "19.99",
            "editableAmount": "19.99",
            "total": "19.99",
            "currency": "<currency>",
            "status": "<status>",
            "priority": "<priority>",
            "needByDate": "2026-01-15",
            "deliveryDate": "2026-01-15",
            "estimatedDeliveryDate": "2026-01-15",
            "startDate": "2026-01-15",
            "endDate": "2026-01-15",
            "unitOfMeasure": "<unitOfMeasure>",
            "unitOfMeasureId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
            "itemId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
            "departmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          }
        ]
      }
    ],
    "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
