Retrieve a project's expenses and budgets

Operation ID: getExpensesSummary

Group: PSA › Expenses

Open in the interactive reference

GET /psa/expenses/summary

Read-only: Reads and returns; changes nothing.

Retrieves a project's expenses and budgets. The response also lists every budget defined for the project in expenseBudgets, and the default catch-all budget in defaultBudget, when one is set. Send the project's numeric psaProjectId in the query string.

Only the expenses array is paginated. budgetMappings covers only the expenses on the current page, and expenseBudgets is the same on every page. The cursor counts expenses from the start, so a page can skip or repeat an expense if expenses are added or removed between requests.

With only View permission on the project, you see only your own expenses. With Edit permission, you see all of the project's expenses.

This endpoint does not follow the standard collection rules in Pagination and querying.

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.
pageCursor 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 expenses per page, between 1 and 200. Defaults to 50. The maximum is 200. Example: 50.

Response

200 Success

Under data (getExpensesSummaryOutput):

Field Type Required Description
expenses array<object> yes The expense entries on this page, each linked to the project through its assigned budget. Example: [{"id":88213,"employeeName":"Priya Natarajan","categoryName":"Airfare","amount":"412.50","amountCurrency":"USD","status":"Approved","billDate":"2026-07-02"}].
expenses[].id number no The unique identifier for the expense entry.
expenses[].expenseReportId number no The id of the expense report this expense belongs to. It is a numeric key, not the UUID that GET accounting/expense-reports/:id takes.
expenses[].employeeName string no The name of the employee who incurred the expense.
expenses[].categoryName string no The name of the expense category.
expenses[].amount decimal no The gross amount of the expense, in the currency given by amountCurrency.
expenses[].amountCurrency string no The currency of amount. Format ISO 4217, for example 'USD'.
expenses[].reimbursableNetAmount decimal no The reimbursable net amount of the expense, after tax and any company-paid portions, in the currency given by reimbursableNetAmountCurrency.
expenses[].reimbursableNetAmountCurrency string no The currency of reimbursableNetAmount. Format ISO 4217, for example 'USD'.
expenses[].status string no The status of the expense entry.
expenses[].notes string no Free-form notes on the expense.
expenses[].billDate date no The date the expense was incurred. Format YYYY-MM-DD.
expenses[].billableExpense string no The billable classification of the expense.
expenses[].expenseReportNumber string no The human-readable number of the expense report.
budgetMappings array<object> yes The mapping of each expense on this page to its assigned budget. It covers only the expenses in this page's expenses array. Example: [{"expenseItemBaseId":88213,"expenseBudgetId":501,"name":"Travel","budget":"10000.00","currency":"USD"}].
budgetMappings[].expenseItemBaseId number yes The id of the expense this mapping is for. It matches an id in the expenses array of this response.
budgetMappings[].expenseBudgetId number yes The id of the budget this expense is mapped to. It matches an id in the expenseBudgets array of this response.
budgetMappings[].name string yes The display name of the budget.
budgetMappings[].budget decimal no The budget amount, in the currency given by currency. Absent when the budget has no amount.
budgetMappings[].currency string no The currency of budget. Format ISO 4217, for example 'USD'. Absent when the budget has no amount.
budgetMappings[].isDefault boolean | null no Whether this is the project's default catch-all budget.
budgetMappings[].billable boolean | null no Whether expenses against this budget are billable to the customer.
budgetMappings[].productId number | null 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.
budgetMappings[].productLineId number | null 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.
budgetMappings[].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.
expenseBudgets array<object> yes Every budget defined for the project. This array is never paginated. Example: [{"id":501,"name":"Travel","budget":"10000.00","currency":"USD","isDefault":false,"lastModifiedDate":"2026-07-02T09:14:22.000Z"}].
expenseBudgets[].id number yes The unique identifier for the budget.
expenseBudgets[].name string yes The display name of the budget.
expenseBudgets[].budget decimal no The budget amount, in the currency given by currency. Absent when the budget has no amount.
expenseBudgets[].currency string no The currency of budget. Format ISO 4217, for example 'USD'. Absent when the budget has no amount.
expenseBudgets[].isDefault boolean yes Whether this is the project's default catch-all budget.
expenseBudgets[].lastModifiedDate date-time no The date and time the budget definition last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ.
expenseBudgets[].billable boolean | null no Whether expenses against this budget are billable to the customer.
expenseBudgets[].productId number | null 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.
expenseBudgets[].productLineId number | null 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.
expenseBudgets[].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.
defaultBudget object no The project's default catch-all budget for expenses with no explicit mapping. Absent when the project has no default budget.
defaultBudget.id number yes The unique identifier for the budget.
defaultBudget.name string yes The display name of the budget.
defaultBudget.budget decimal no The budget amount, in the currency given by currency. Absent when the budget has no amount.
defaultBudget.currency string no The currency of budget. Format ISO 4217, for example 'USD'. Absent when the budget has no amount.
defaultBudget.isDefault boolean yes Always true, because this is the default budget.
defaultBudget.lastModifiedDate date-time no The date and time the budget definition last changed, in UTC. Format YYYY-MM-DDTHH:mm:ss.sssZ.
defaultBudget.billable boolean | null no Whether expenses against this budget are billable to the customer.
defaultBudget.productId number | null 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.
defaultBudget.productLineId number | null 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.
defaultBudget.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 the expenses array. Example: {"hasMore":false}.
pagination.nextCursor string no The cursor for the next page. Pass it as the pageCursor query parameter. Absent on the last page.
pagination.hasMore boolean yes True when more expenses remain beyond this page.
{
  "data": {
    "expenses": [
      {
        "id": 88213,
        "employeeName": "Priya Natarajan",
        "categoryName": "Airfare",
        "amount": "412.50",
        "amountCurrency": "USD",
        "status": "Approved",
        "billDate": "2026-07-02"
      }
    ],
    "budgetMappings": [
      {
        "expenseItemBaseId": 88213,
        "expenseBudgetId": 501,
        "name": "Travel",
        "budget": "10000.00",
        "currency": "USD"
      }
    ],
    "expenseBudgets": [
      {
        "id": 501,
        "name": "Travel",
        "budget": "10000.00",
        "currency": "USD",
        "isDefault": false,
        "lastModifiedDate": "2026-07-02T09:14:22.000Z"
      }
    ],
    "defaultBudget": {
      "id": 0,
      "name": "<name>",
      "budget": "19.99",
      "currency": "<currency>",
      "isDefault": true,
      "lastModifiedDate": "2026-01-15T09:30:00.000Z",
      "billable": true,
      "productId": 0,
      "productLineId": 0,
      "salesOrderId": 0
    },
    "pagination": {
      "hasMore": false
    }
  },
  "diagnostics": [
    {
      "code": "<code>",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": "<details>"
    }
  ]
}

Errors

Code Status
EMPLOYEE_NOT_FOUND 400

Statuses