List a project's expense budgets
Operation ID: getExpenseBudgets
Group: PSA › Expenses
Open in the interactive reference
GET /psa/expenses/budgets
Read-only: Reads and returns; changes nothing.
Lists the expense budgets defined for a PSA project. Send the project's numeric psaProjectId in the query string. You need view access to that project.
This endpoint does not follow the standard collection rules in Pagination and querying.
- Page with
pageSize(default 50, maximum 200, minimum 1) andcursor, notpage[size]andpage[cursor]. - The response contains the records in
data.itemsand the next page's cursor indata.pagination.nextCursor. - Send
psaProjectId, which is required. To get only the default budget, sendisDefault=true. - There is no
sortorfields.
This endpoint ignores any query parameter it does not declare, and returns no error. A request that follows the standard rules therefore gets the first page, unfiltered, every time.
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. |
psaProjectId |
query | number | yes | The id of the PSA project. It is the numeric key, not the UUID that GET psa/projects/:id takes. Example: 32341. |
isDefault |
query | boolean | no | When true, return only the project's default catch-all budget. When false or omitted, return all of the project's budgets. False does not filter to non-default budgets. |
cursor |
query | string | no | The cursor from the previous response's data.pagination.nextCursor. Omit on the first request. |
pageSize |
query | number | no | The number of budgets per page, between 1 and 200. Defaults to 50. A value above 200 is treated as 200, not rejected. Example: 50. |
Response
200 Success
Under data (getExpenseBudgetsOutput):
| Field | Type | Required | Description |
|---|---|---|---|
items |
array<object> | yes | The project's budgets on this page. An empty array when the project has no budgets. Example: [{"id":501,"name":"Travel","budget":"10000.00","currency":"USD","isDefault":false,"billable":true,"lastModifiedDate":"2026-07-02T09:14:22.000Z"},{"id":502,"name":"General","budget":"5000.00","currency":"USD","isDefault":true,"lastModifiedDate":"2026-06-18T11:02:47.000Z"}]. |
items[].id |
number | yes | The unique identifier for the budget. |
items[].name |
string | yes | The display name of the budget. |
items[].budget |
decimal | no | The budget amount, in the currency given by currency. Absent when the budget has no amount. |
items[].currency |
string | no | The currency of budget. Format ISO 4217, for example 'USD'. Absent when the budget has no amount. |
items[].isDefault |
boolean | yes | Whether this is the project's default catch-all budget. |
items[].lastModifiedDate |
date-time | no | The date and time the budget definition last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ. |
items[].billable |
boolean | no | Whether expenses against this budget are billable to the customer. |
items[].productId |
number | no | The id of the product tied to this budget. It is a numeric key, not the UUID that GET accounting/products/:id takes. Absent when the budget is not tied to a product. |
items[].productLineId |
number | no | The id of the product line tied to this budget. It is a numeric key, not the UUID that GET accounting/product-lines/:id takes. Absent when the budget is not tied to a product line. |
items[].salesOrderId |
number | no | The id of the sales order this budget bills against. It is a numeric key, not the UUID that GET accounting/sales-orders/:id takes. |
pagination |
object | yes | The pagination cursor for this page. Example: {"hasMore":false}. |
pagination.nextCursor |
string | no | The cursor for the next page. Pass it as the cursor query parameter. Absent on the last page. |
pagination.hasMore |
boolean | yes | True when more budgets remain beyond this page. |
{
"data": {
"items": [
{
"id": 501,
"name": "Travel",
"budget": "10000.00",
"currency": "USD",
"isDefault": false,
"billable": true,
"lastModifiedDate": "2026-07-02T09:14:22.000Z"
},
{
"id": 502,
"name": "General",
"budget": "5000.00",
"currency": "USD",
"isDefault": true,
"lastModifiedDate": "2026-06-18T11:02:47.000Z"
}
],
"pagination": {
"hasMore": false
}
},
"diagnostics": [
{
"code": "<code>",
"message": "<message>",
"severity": "error",
"path": [
"<path>"
],
"details": "<details>"
}
]
}
Statuses
400— Invalid request or business failure401— The request carries no valid access token.403— Not authorized404— Not found429— Too many requests from this client address. The response has no body and noRetry-Afterheader.500— Internal server error