# List projects

Operation ID: `projects`

Group: PSA › Projects

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

`GET /psa/projects`

Read-only: Reads and returns; changes nothing.

Lists projects. Unless you are a super admin, the list includes only projects where you are a team member. Archived projects and projects whose status is 'Planning' or 'PlanningDraft' are left out unless you send showArchivedProjects=true or showPlanningProjects=true.

There is no endpoint to find a project by name or code, or to list the projects of one department or one sales arrangement. To find a project by name, list the projects and match the name in your own code.

## 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`. |
| `showArchivedProjects` | query | boolean | no | When true, archived projects are included in the results. Set via ?showArchivedProjects=true, not a filter[] entry. |
| `showPlanningProjects` | query | boolean | no | When true, projects in Planning and PlanningDraft status are included in the results. Set via ?showPlanningProjects=true, not a filter[] entry. |

## Query surface

- `id` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between, like
- `lastModifiedDate` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- `category` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between, like
- `status` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between, like
- `currency` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between, like
- `invoiced` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- `startDate` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- `endDate` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- `projectTypeId` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- `quoteId` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- `opportunityId` — filter by eq, ne, gt, gte, lt, lte, in, notIn, between
- Orderable: id, lastModifiedDate, category, status, currency, invoiced, startDate, endDate
- Selectable: id, lastModifiedDate, name, code, category, status, currency, invoiced, startDate, endDate, notes, enforceActivityDateRange, budgetAmount, budgetCurrency, departmentId, teamId, teamName, teamStartDate, teamEndDate, salesRepresentativeId, salesRepresentativeName, projectTypeId, projectTypeName, quoteId, quoteNumber, opportunityId, opportunityName, opportunityCurrency, salesArrangementId, salesArrangementCurrency, salesArrangementCustomerId, salesArrangementCustomerName, salesArrangementEntityId, salesArrangementEntityName, revenueRecordedTimeToDate, revenueAccomplishedMilestones, revenueFixedFeeToDate, revenueToDate, budgetRemaining
- `page[size]` — Page size
- `page[cursor]` — Opaque continuation cursor

## Response

`200` Success

Under `data`, an array of projectsRow:

| Field | Type | Required | Filter | Sort | Description |
| --- | --- | --- | --- | --- | --- |
| `id` | string | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`), Pattern (`like`) | yes | The unique identifier for the project. |
| `lastModifiedDate` | date-time \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | yes | The date and time the project last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
| `name` | string \| null | no | no | no | The display name of the project. |
| `code` | string \| null | no | no | no | The project code, for example 'PSA-29767'. Absent when none has been set. |
| `category` | string \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`), Pattern (`like`) | yes | The project category. Possible values: 'Billable', 'Internal', 'NonBillable'. |
| `status` | string \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`), Pattern (`like`) | yes | The project status. Possible values: 'Tentative', 'Planning', 'PlanningDraft', 'NotStarted', 'InProgress', 'Paused', 'Completed', 'Cancelled'. |
| `currency` | string \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`), Pattern (`like`) | yes | The project's default currency. Format ISO 4217, for example 'USD'. It applies to revenueRecordedTimeToDate, revenueAccomplishedMilestones, revenueFixedFeeToDate, revenueToDate, and budgetRemaining. |
| `invoiced` | boolean \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | yes | Whether the project is marked as invoiced. |
| `startDate` | date \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | yes | The project start date. Format YYYY-MM-DD. |
| `endDate` | date \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | yes | The project end date. Format YYYY-MM-DD. |
| `notes` | string \| null | no | no | no | Free-form notes about the project. |
| `enforceActivityDateRange` | boolean \| null | no | no | no | Whether time entries must fall within the project's startDate and endDate. |
| `budgetAmount` | decimal \| null | no | no | no | The project budget amount, in budgetCurrency. |
| `budgetCurrency` | string \| null | no | no | no | The currency of budgetAmount. Format ISO 4217, for example 'USD'. |
| `departmentId` | number \| null | no | no | no | The numeric identifier of the department the project is allocated to. GET people/departments/:id takes a UUID, so the number cannot be used to fetch the department. |
| `teamId` | number \| null | no | no | no | The numeric identifier of the team assigned to this project. GET people/teams/:id takes a UUID, so the number cannot be used to fetch the team. |
| `teamName` | string \| null | no | no | no | The display name of the team. |
| `teamStartDate` | date \| null | no | no | no | The team's start date, which may differ from startDate. Format YYYY-MM-DD. |
| `teamEndDate` | date \| null | no | no | no | The team's end date, which may differ from endDate. Format YYYY-MM-DD. |
| `salesRepresentativeId` | number \| null | no | no | no | The numeric identifier of the sales representative, an employee. There is no endpoint for it. |
| `salesRepresentativeName` | string \| null | no | no | no | The display name of the sales representative. |
| `projectTypeId` | number \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | no | The numeric identifier of the project type. GET psa/project-types/:id takes a UUID, so the number cannot be used to fetch the project type. |
| `projectTypeName` | string \| null | no | no | no | The display name of the project type. |
| `quoteId` | number \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | no | The numeric identifier of the CRM quote this project was created from. GET crm/quotes/:id takes a UUID, so the number cannot be used to fetch the quote. |
| `quoteNumber` | string \| null | no | no | no | The quote number. |
| `opportunityId` | number \| null | no | Exact (`eq`, `ne`), Range (`gt`, `gte`, `lt`, `lte`, `between`), Any of (`in`, `notIn`) | no | The numeric identifier of the CRM opportunity this project is linked to. GET crm/opportunities/:id takes a UUID, so the number cannot be used to fetch the opportunity. |
| `opportunityName` | string \| null | no | no | no | The display name of the opportunity. |
| `opportunityCurrency` | string \| null | no | no | no | The currency of the opportunity. Format ISO 4217, for example 'USD'. |
| `salesArrangementId` | number \| null | no | no | no | The numeric identifier of the sales arrangement that links the project to billing terms. There is no endpoint for it. |
| `salesArrangementCurrency` | string \| null | no | no | no | The functional currency of the sales arrangement. Format ISO 4217, for example 'USD'. |
| `salesArrangementCustomerId` | number \| null | no | no | no | The numeric identifier of the customer on the sales arrangement. GET accounting/customers/:id takes a UUID, so the number cannot be used to fetch the customer. |
| `salesArrangementCustomerName` | string \| null | no | no | no | The display name of the customer on the sales arrangement. |
| `salesArrangementEntityId` | number \| null | no | no | no | The numeric identifier of the legal entity on the sales arrangement. There is no endpoint for it. |
| `salesArrangementEntityName` | string \| null | no | no | no | The display name of the legal entity on the sales arrangement. |
| `revenueRecordedTimeToDate` | decimal \| null | no | no | no | The revenue from recorded time up to today, in the project currency. Absent when the project has no time entries. |
| `revenueAccomplishedMilestones` | decimal \| null | no | no | no | The revenue from accomplished and invoiced milestones, in the project currency. Absent when the project has no completed milestones. |
| `revenueFixedFeeToDate` | decimal \| null | no | no | no | The fixed-fee revenue to date, in the project currency. Absent when the project has no fixed fees. |
| `revenueToDate` | decimal \| null | no | no | no | The total revenue to date, in the project currency: revenueRecordedTimeToDate + revenueAccomplishedMilestones + revenueFixedFeeToDate. |
| `budgetRemaining` | decimal \| null | no | no | no | The budget remaining, in the project currency: budgetAmount - revenueToDate. |

```json
{
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "lastModifiedDate": "2026-01-15T09:30:00.000Z",
      "name": "<name>",
      "code": "<code>",
      "category": "<category>",
      "status": "<status>",
      "currency": "<currency>",
      "invoiced": true,
      "startDate": "2026-01-15",
      "endDate": "2026-01-15",
      "notes": "<notes>",
      "enforceActivityDateRange": true,
      "budgetAmount": "19.99",
      "budgetCurrency": "<budgetCurrency>",
      "departmentId": 0,
      "teamId": 0,
      "teamName": "<teamName>",
      "teamStartDate": "2026-01-15",
      "teamEndDate": "2026-01-15",
      "salesRepresentativeId": 0,
      "salesRepresentativeName": "<salesRepresentativeName>",
      "projectTypeId": 0,
      "projectTypeName": "<projectTypeName>",
      "quoteId": 0,
      "quoteNumber": "<quoteNumber>",
      "opportunityId": 0,
      "opportunityName": "<opportunityName>",
      "opportunityCurrency": "<opportunityCurrency>",
      "salesArrangementId": 0,
      "salesArrangementCurrency": "<salesArrangementCurrency>",
      "salesArrangementCustomerId": 0,
      "salesArrangementCustomerName": "<salesArrangementCustomerName>",
      "salesArrangementEntityId": 0,
      "salesArrangementEntityName": "<salesArrangementEntityName>",
      "revenueRecordedTimeToDate": "19.99",
      "revenueAccomplishedMilestones": "19.99",
      "revenueFixedFeeToDate": "19.99",
      "revenueToDate": "19.99",
      "budgetRemaining": "19.99"
    }
  ],
  "pagination": {
    "hasMore": true,
    "nextCursor": "<nextCursor>"
  }
}
```

## 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
