# Retrieve a project

Operation ID: `getPsaProject`

Group: PSA › Projects

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

`GET /psa/projects/{id}`

Read-only: Reads and returns; changes nothing.

Retrieves a project. Use the project's id, not its code or the numeric psaProjectId that other PSA endpoints return.

The response includes the project's budget, team, sales arrangement, and revenue to date, and has the same fields as each project from GET psa/projects.

The request fails with NOT_FOUND for an archived project and for a project whose status is 'Planning' or 'PlanningDraft'. It also fails with NOT_FOUND when you are not a member of the project's team, unless you are a super admin.

## 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`. |
| `id` | path | string | yes | The unique identifier of the project you want to retrieve. Example: `"3b7d5e9c-1a24-4f80-9c6d-2e8f70b13a45"`. |

## Response

`200` Success

Under `data` (getPsaProjectOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | The unique identifier for the project. Example: `"3b7d5e9c-1a24-4f80-9c6d-2e8f70b13a45"`. |
| `lastModifiedDate` | date-time | yes | The date and time the project last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. Example: `"2026-08-12T09:30:00.000Z"`. |
| `name` | string | yes | The display name of the project. Example: `"Spire Digital Rollout"`. |
| `code` | string | no | The project code, for example 'PSA-29767'. Absent when none has been set. Example: `"PSA-29767"`. |
| `category` | string | yes | The project category. Possible values: 'Billable', 'Internal', 'NonBillable'. Example: `"Billable"`. |
| `status` | string | yes | The project status. Possible values: 'Tentative', 'Planning', 'PlanningDraft', 'NotStarted', 'InProgress', 'Paused', 'Completed', 'Cancelled'. Example: `"NotStarted"`. |
| `currency` | string | yes | The project's default currency. Format ISO 4217, for example 'USD'. It applies to revenueRecordedTimeToDate, revenueAccomplishedMilestones, revenueFixedFeeToDate, revenueToDate, and budgetRemaining. Example: `"USD"`. |
| `invoiced` | boolean | yes | Whether the project is marked as invoiced. Example: `false`. |
| `startDate` | date | yes | The project start date. Format YYYY-MM-DD. Example: `"2026-08-03"`. |
| `endDate` | date | yes | The project end date. Format YYYY-MM-DD. Example: `"2026-12-18"`. |
| `notes` | string | no | Free-form notes about the project. |
| `enforceActivityDateRange` | boolean | no | Whether time entries must fall within the project's startDate and endDate. |
| `budgetAmount` | decimal | no | The project budget amount, in budgetCurrency. |
| `budgetCurrency` | string | no | The currency of budgetAmount. Format ISO 4217, for example 'USD'. |
| `departmentId` | number | 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 | yes | 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. Example: `89969`. |
| `teamName` | string | no | The display name of the team. |
| `teamStartDate` | date | no | The team's start date, which may differ from startDate. Format YYYY-MM-DD. |
| `teamEndDate` | date | no | The team's end date, which may differ from endDate. Format YYYY-MM-DD. |
| `salesRepresentativeId` | number | no | The numeric identifier of the sales representative, an employee. There is no endpoint for it. |
| `salesRepresentativeName` | string | no | The display name of the sales representative. |
| `projectTypeId` | number | 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 | no | The display name of the project type. |
| `quoteId` | number | 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 | no | The quote number. |
| `opportunityId` | number | 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 | no | The display name of the opportunity. |
| `opportunityCurrency` | string | no | The currency of the opportunity. Format ISO 4217, for example 'USD'. |
| `salesArrangementId` | number | no | The numeric identifier of the sales arrangement that links the project to billing terms. There is no endpoint for it. |
| `salesArrangementCurrency` | string | no | The functional currency of the sales arrangement. Format ISO 4217, for example 'USD'. |
| `salesArrangementCustomerId` | number | 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 | no | The display name of the customer on the sales arrangement. |
| `salesArrangementEntityId` | number | no | The numeric identifier of the legal entity on the sales arrangement. There is no endpoint for it. |
| `salesArrangementEntityName` | string | no | The display name of the legal entity on the sales arrangement. |
| `revenueRecordedTimeToDate` | decimal | no | The revenue from recorded time up to today, in the project currency. Absent when the project has no time entries. |
| `revenueAccomplishedMilestones` | decimal | no | The revenue from accomplished and invoiced milestones, in the project currency. Absent when the project has no completed milestones. |
| `revenueFixedFeeToDate` | decimal | no | The fixed-fee revenue to date, in the project currency. Absent when the project has no fixed fees. |
| `revenueToDate` | decimal | no | The total revenue to date, in the project currency: revenueRecordedTimeToDate + revenueAccomplishedMilestones + revenueFixedFeeToDate. |
| `budgetRemaining` | decimal | no | The budget remaining, in the project currency: budgetAmount - revenueToDate. |

```json
{
  "data": {
    "id": "3b7d5e9c-1a24-4f80-9c6d-2e8f70b13a45",
    "lastModifiedDate": "2026-08-12T09:30:00.000Z",
    "name": "Spire Digital Rollout",
    "code": "PSA-29767",
    "category": "Billable",
    "status": "NotStarted",
    "currency": "USD",
    "invoiced": false,
    "startDate": "2026-08-03",
    "endDate": "2026-12-18",
    "notes": "<notes>",
    "enforceActivityDateRange": true,
    "budgetAmount": "19.99",
    "budgetCurrency": "<budgetCurrency>",
    "departmentId": 0,
    "teamId": 89969,
    "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"
  },
  "diagnostics": [
    {
      "code": "<code>",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": "<details>"
    }
  ]
}
```

## Errors

| Code | Status |
| --- | --- |
| `NOT_FOUND` | 400 |

## Statuses

- `400` — Invalid request or business failure. Codes: NOT_FOUND
- `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
