> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pazy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Expense List API

> Retrieve a paginated list of expenses with filters by date, state, employee, amount, and tags

## Authentication

All requests require an API key in the request headers.

**Headers:**

```
Authorization: Api-Key YOUR_API_KEY
```

## Request

### Query Parameters

| Parameter        | Type            | Required | Description                                                                                                                                                                                                                            |
| ---------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sortBy`         | string          | No       | Field to sort results by. Allowed values: `total_amount`, `date_created`, `date_updated`, `item_count`.                                                                                                                                |
| `sortOrder`      | string          | No       | Sort direction. Allowed values: `asc` (ascending), `desc` (descending).                                                                                                                                                                |
| `sortNullOrder`  | string          | No       | Where to place results with null values in the sorted field. Allowed values: `first`, `last`.                                                                                                                                          |
| `limit`          | integer         | No       | Number of records to return. Min 1, Max 100, Default 30.                                                                                                                                                                               |
| `cursor`         | string          | No       | Cursor for pagination. Use the `nextCursor` value returned by the previous response.                                                                                                                                                   |
| `startDate`      | string          | No       | Start date for filtering (ISO 8601 UTC format: `YYYY-MM-DDTHH:mm:ssZ`).                                                                                                                                                                |
| `endDate`        | string          | No       | End date for filtering (ISO 8601 UTC format: `YYYY-MM-DDTHH:mm:ssZ`).                                                                                                                                                                  |
| `state`          | array           | No       | Expense states to filter by. Allowed values: `DRAFTED`, `PENDING`, `APPROVED`, `OUT_OF_POLICY`. Currently supports exactly one state. Note: `DECLINED` expenses may appear in unfiltered results but cannot be used as a filter value. |
| `employeeName`   | string          | No       | Filter by the name of the employee who raised the expense (partial match).                                                                                                                                                             |
| `tagId`          | integer         | No       | Filter expenses containing this organization tag id.                                                                                                                                                                                   |
| `minAmount`      | number          | No       | Filter expenses with amount greater than or equal to this value.                                                                                                                                                                       |
| `maxAmount`      | number          | No       | Filter expenses with amount less than or equal to this value.                                                                                                                                                                          |
| `tag[<tagSlug>]` | string or array | No       | Filter expenses by the value of a specific tag. See [Filtering by Tags](#filtering-by-tags).                                                                                                                                           |

### Filtering by Tags

Expenses can be filtered by any tag configured for your organization using the `tag[<tagSlug>]` query parameter, where `<tagSlug>` is the tag's slug (the `id` returned by the [Tag List API](/apis/tag-list)).

```
?tag[cost-center]=Engineering&tag[project]=Apollo
```

**Matching rules by tag type**

| Tag `dataType`    | Accepted value                                                                          | Matching                                                                                                                                                            |
| ----------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DROPDOWN`        | The tag value text (for example `Engineering`) or the tag value id (for example `1024`) | Exact match, case-insensitive. Both forms are accepted for the same tag and can be mixed. Get the values and their ids from the [Tag Detail API](/apis/tag-detail). |
| `VARCHAR` (text)  | The text entered on the expense                                                         | Exact match, case-insensitive — `engineering` matches `Engineering`, but `Eng` does not match `Engineering`                                                         |
| `DATETIME` (date) | Date in `YYYY-MM-DD` format (for example `2026-01-15`)                                  | Exact match on the date                                                                                                                                             |

**Combining filters**

* Repeat the parameter to pass multiple values for the same tag — the values are combined with **OR**: `?tag[cost-center]=Engineering&tag[cost-center]=Marketing` returns expenses tagged with either value
* Pass different tag slugs to combine them with **AND**: `?tag[cost-center]=Engineering&tag[project]=Apollo` returns only expenses that carry both
* Values must match exactly (case-insensitive); partial matches are not supported
* Filtering is supported for `DROPDOWN`, `VARCHAR`, and `DATETIME` tags. Numeric tags (`NUMBER`, `NUMERIC`) cannot be used as filters
* A slug that does not exist as a tag in your organization is ignored rather than rejected — verify slugs against the [Tag List API](/apis/tag-list) if a filter returns unexpected results

## Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.pazy.io/v1.0/expenses?limit=30&state=APPROVED&tag%5Bcost-center%5D=Engineering" \
    -H "Authorization: Api-Key YOUR_API_KEY"
  ```

  ```javascript JavaScript (Fetch API) theme={null}
  const params = new URLSearchParams({
    limit: '30',
    state: 'APPROVED',
    'tag[cost-center]': 'Engineering'
  });
  const response = await fetch(`https://api.pazy.io/v1.0/expenses?${params}`, {
    method: 'GET',
    headers: {
      'Authorization': 'Api-Key YOUR_API_KEY'
    }
  });

  const result = await response.json();
  ```

  ```python Python (requests) theme={null}
  import requests

  url = "https://api.pazy.io/v1.0/expenses"
  headers = {
      "Authorization": "Api-Key YOUR_API_KEY"
  }
  params = {
      "limit": 30,
      "state": "APPROVED",
      "tag[cost-center]": "Engineering"
  }

  response = requests.get(url, headers=headers, params=params)
  result = response.json()
  ```
</CodeGroup>

## Success Response

**HTTP Status:** `200 OK`

**Response Fields:**

| Field                                            | Type             | Description                                                                                                                                                                                          |
| ------------------------------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`                                             | boolean          | Indicates whether the request was successful                                                                                                                                                         |
| `data`                                           | object           | Contains the expense list response data                                                                                                                                                              |
| `data.expenses`                                  | array            | List of expenses                                                                                                                                                                                     |
| `data.expenses[].id`                             | string           | Unique identifier (slug) for the expense                                                                                                                                                             |
| `data.expenses[].state`                          | string           | Approval lifecycle state of the expense. See [Field Reference → state](#state-—-expense-approval-state) for all values.                                                                              |
| `data.expenses[].syncState`                      | string           | Accounting sync state. See [Field Reference → syncState](#syncstate-—-accounting-sync-state) for all values.                                                                                         |
| `data.expenses[].expenseType`                    | string           | Type of the expense                                                                                                                                                                                  |
| `data.expenses[].paymentState`                   | string           | Bank transaction state. Always `FINISHED` in list responses. See [Field Reference → paymentState](#paymentstate-—-bank-transaction-state) for details.                                               |
| `data.expenses[].currency`                       | string           | Currency code (e.g., `INR`)                                                                                                                                                                          |
| `data.expenses[].totalAmount`                    | number           | Total amount of the expense                                                                                                                                                                          |
| `data.expenses[].itemCount`                      | integer          | Number of line items in the expense                                                                                                                                                                  |
| `data.expenses[].description`                    | string           | Description of the expense                                                                                                                                                                           |
| `data.expenses[].identifier`                     | string           | Human-readable identifier / number for the expense                                                                                                                                                   |
| `data.expenses[].selfUrl`                        | string           | Shareable URL for viewing the expense in the web interface                                                                                                                                           |
| `data.expenses[].transactionData`                | object           | Transaction details for the expense                                                                                                                                                                  |
| `data.expenses[].transactionData.utr`            | string           | Unique Transaction Reference (UTR) of the payment                                                                                                                                                    |
| `data.expenses[].transactionData.dateConfirmed`  | string           | Date the transaction was confirmed (falls back to expense date or creation date)                                                                                                                     |
| `data.expenses[].transactionData.narration`      | string           | Bank narration for the transaction                                                                                                                                                                   |
| `data.expenses[].transactionData.ledgerId`       | string or null   | Ledger / instrument identifier the transaction is mapped to                                                                                                                                          |
| `data.expenses[].transactionData.isSelfTransfer` | boolean          | Whether the transaction is a self-transfer (between the user's own accounts) rather than a payment to an external merchant. See [Field Reference → isSelfTransfer](#transactiondata-isselftransfer). |
| `data.expenses[].merchant`                       | object           | Merchant details                                                                                                                                                                                     |
| `data.expenses[].merchant.name`                  | string or null   | Merchant name                                                                                                                                                                                        |
| `data.expenses[].merchant.vpa`                   | string or null   | Merchant VPA (UPI address)                                                                                                                                                                           |
| `data.expenses[].initiator`                      | object           | Details of the user who raised the expense                                                                                                                                                           |
| `data.expenses[].initiator.slug`                 | string           | Unique slug identifier of the initiator                                                                                                                                                              |
| `data.expenses[].initiator.name`                 | string           | Full name of the initiator                                                                                                                                                                           |
| `data.expenses[].initiator.email`                | string           | Email address of the initiator                                                                                                                                                                       |
| `data.expenses[].initiator.id`                   | string or null   | Internal id of the initiator                                                                                                                                                                         |
| `data.expenses[].cardInfo`                       | object or null   | Card details if the expense was paid by card. `null` otherwise                                                                                                                                       |
| `data.expenses[].cardInfo.maskedCardNumber`      | string           | Masked card number                                                                                                                                                                                   |
| `data.expenses[].cardInfo.description`           | string           | Card description                                                                                                                                                                                     |
| `data.expenses[].cardInfo.name`                  | string           | Card name                                                                                                                                                                                            |
| `data.expenses[].syncStatus`                     | string           | Human-readable accounting sync status label. See [Field Reference → syncStatus](#syncstatus-—-human-readable-accounting-sync-status-label) for all values.                                           |
| `data.expenses[].status`                         | string           | Human-readable computed status label. See [Field Reference → status](#status-—-human-readable-expense-status-label) for all values.                                                                  |
| `data.expenses[].tags`                           | object           | Tags applied to the expense, keyed by tag slug. Absent when the expense carries no tags.                                                                                                             |
| `data.expenses[].tags.<tagSlug>`                 | array            | Values applied to the expense for this tag                                                                                                                                                           |
| `data.expenses[].tags.<tagSlug>[].id`            | number           | Identifier of the applied tag. For `DROPDOWN` tags this is the tag value id (usable in the `tag[<tagSlug>]` filter); for text, date, and number tags this is the tag field id                        |
| `data.expenses[].tags.<tagSlug>[].value`         | string or number | The value applied on the expense. Date tags are returned as `YYYY-MM-DD`                                                                                                                             |
| `data.totalAmountAndCountByCurrency`             | array            | Aggregated total amount and count of matching expenses, grouped by currency                                                                                                                          |
| `data.totalAmountAndCountByCurrency[].currency`  | string           | Currency code for the aggregate                                                                                                                                                                      |
| `data.totalAmountAndCountByCurrency[].amount`    | number or string | Sum of expense amounts in this currency                                                                                                                                                              |
| `data.totalAmountAndCountByCurrency[].count`     | number or string | Number of expenses in this currency                                                                                                                                                                  |
| `data.context`                                   | object           | Pagination metadata                                                                                                                                                                                  |
| `data.context.count`                             | number           | Number of expenses returned in this page                                                                                                                                                             |
| `data.context.hasMore`                           | boolean          | Indicates whether there are more expenses to fetch                                                                                                                                                   |
| `data.context.nextCursor`                        | string or null   | Cursor to fetch the next page. `null` when there are no more results                                                                                                                                 |

### Field Reference

#### `state` — Expense approval state

The approval lifecycle state of the expense.

| Value           | Description                                                                     |
| --------------- | ------------------------------------------------------------------------------- |
| `DRAFTED`       | Expense is open/in draft. It has not been submitted for approval yet.           |
| `PENDING`       | Expense has been submitted and is awaiting approval from the assigned approver. |
| `APPROVED`      | Expense has been approved by the approver.                                      |
| `OUT_OF_POLICY` | Expense was flagged as out of policy by an approver or admin.                   |
| `DECLINED`      | Expense was declined by the approver.                                           |

#### `syncState` — Accounting sync state

Indicates whether the expense has been synced to the connected accounting system (e.g., Tally, Zoho).

| Value        | Description                                                                                   |
| ------------ | --------------------------------------------------------------------------------------------- |
| `NOT_SYNCED` | Expense has not been synced to any accounting integration. This is the default state.         |
| `QUEUED`     | Expense is queued for sync to the accounting integration. The sync will be processed shortly. |
| `SYNCED`     | Expense has been successfully synced to the accounting integration.                           |
| `SKIPPED`    | Sync was deliberately skipped by an admin — the expense was moved to history without syncing. |

#### `paymentState` — Bank transaction state

Indicates the state of the underlying payment/bank transaction for the expense.

| Value      | Description                                                                                                                                                              |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `FINISHED` | Payment has been completed and settled successfully. This is the only value returned by the list API — expenses with incomplete payments are excluded from list results. |
| `PENDING`  | Payment is still being processed by the bank. These expenses do **not** appear in list API results.                                                                      |
| `FAILED`   | Payment transaction failed (e.g., card authorization failure). These expenses do **not** appear in list API results.                                                     |
| `REJECTED` | Payment was rejected during just-in-time (JIT) card authorization. These expenses do **not** appear in list API results.                                                 |

<Note>
  The list API only returns expenses where `paymentState` is `FINISHED`. You will always see `"FINISHED"` for this field in list responses. Expenses with other payment states are accessible only in the Pazy web app.
</Note>

#### `status` — Human-readable expense status label

A computed label summarizing the overall lifecycle position of the expense. This value is derived from a combination of `state`, `syncState`, `paymentState`, and internal fields. The API key context determines the label set (admin perspective).

| Value           | Label          | Condition                                                          |
| --------------- | -------------- | ------------------------------------------------------------------ |
| `OPEN`          | Open           | Drafted, not synced, payment finished                              |
| `FOR_APPROVAL`  | Under Approval | Pending approval, not synced, payment finished                     |
| `OUT_OF_POLICY` | Out of Policy  | Out of policy or declined, not synced, payment finished            |
| `ACCOUNTING`    | Ready To Sync  | Approved, not yet synced or queued, payment finished               |
| `HISTORY`       | History        | Approved and synced/skipped; or out-of-policy/declined and skipped |
| `UNKNOWN`       | Unknown        | Unrecognized state combination (rare)                              |

#### `syncStatus` — Human-readable accounting sync status label

A computed label describing the expense's position in the accounting sync pipeline. Relevant when an accounting integration (Tally, Zoho, etc.) is connected.

| Value              | Label                   | Description                                                                             |
| ------------------ | ----------------------- | --------------------------------------------------------------------------------------- |
| `SYNCED`           | Synced                  | Successfully synced to the accounting system.                                           |
| `QUEUED_FOR_SYNC`  | In Queue                | Expense is in the sync queue, waiting to be processed.                                  |
| `SYNC_ERROR`       | Sync Error              | Sync was attempted but failed. Retry or manual intervention needed.                     |
| `SKIPPED`          | Skipped                 | Sync was manually skipped by an admin.                                                  |
| `READY_TO_SYNC`    | Ready To Sync           | Expense is approved and has all required accounting fields — ready to be synced.        |
| `MISSING_FIELDS`   | Accounting Info Missing | Required accounting fields (expense head, vendor, ledger mapping, etc.) are not filled. |
| `MISSING_RECEIPTS` | Accounting Info Missing | Required receipt/document is not attached to the expense.                               |

#### `transactionData.isSelfTransfer`

A boolean indicating whether the underlying payment was a self-transfer (a transfer between the user's own accounts) rather than a payment to an external merchant or vendor.

| Value   | Description                                                                  |
| ------- | ---------------------------------------------------------------------------- |
| `true`  | The transaction was a self-transfer between the user's own accounts/wallets. |
| `false` | Normal transaction — payment was made to a third-party merchant or vendor.   |

### Response Example

```json theme={null}
{
  "ok": true,
  "data": {
    "expenses": [
      {
        "id": "expense_identifier",
        "state": "APPROVED",
        "syncState": "SYNCED",
        "expenseType": "GENERAL",
        "paymentState": "FINISHED",
        "currency": "INR",
        "totalAmount": 1500.00,
        "itemCount": 2,
        "description": "Team lunch",
        "identifier": "EXP-2026-001",
        "selfUrl": "https://app.pazy.io/p/expense/expense_identifier",
        "transactionData": {
          "utr": "123456789012",
          "dateConfirmed": "2026-01-15T10:30:00Z",
          "narration": "UPI/abc@bank/Team lunch",
          "ledgerId": "ledger_identifier",
          "isSelfTransfer": false
        },
        "merchant": {
          "name": "ABC Restaurant",
          "vpa": "abc@bank"
        },
        "initiator": {
          "slug": "user_identifier",
          "name": "John Doe",
          "email": "john@example.com",
          "id": "123"
        },
        "cardInfo": {
          "maskedCardNumber": "XXXX XXXX XXXX 1234",
          "description": "Corporate Card",
          "name": "John Doe"
        },
        "syncStatus": "Synced",
        "status": "Approved",
        "tags": {
          "cost-center": [
            {
              "id": 1024,
              "value": "Engineering"
            }
          ],
          "project": [
            {
              "id": 44,
              "value": "Apollo"
            }
          ],
          "invoice-received-on": [
            {
              "id": 45,
              "value": "2026-01-15"
            }
          ]
        }
      }
    ],
    "totalAmountAndCountByCurrency": [
      {
        "currency": "INR",
        "amount": "1500.00",
        "count": "1"
      }
    ],
    "context": {
      "count": 30,
      "hasMore": true,
      "nextCursor": "30"
    }
  }
}
```

## Error Responses

### Validation Error

**HTTP Status:** `400 Bad Request`

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed: /query/state: must be equal to one of the allowed values"
  }
}
```

### Access Denied

**HTTP Status:** `403 Forbidden`

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "ACCESS_DENIED",
    "message": "Access denied: You can only view vendors you own"
  }
}
```

### Authentication Errors

**HTTP Status:** `401 Unauthorized`

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "MISSING_CREDENTIALS",
    "message": "Missing Credentials"
  }
}
```

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid API Key"
  }
}
```

### Permission Errors

**HTTP Status:** `403 Forbidden`

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "Permission check failed - PERMISSION_CHECK_FAILED"
  }
}
```

### Internal Error

**HTTP Status:** `500 Internal Server Error`

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Internal error"
  }
}
```

## Best Practices

* Use `cursor` and `limit` together to paginate; pass the `nextCursor` from the response as the `cursor` value for the next call
* `startDate` and `endDate` are filtered against the expense date — provide both for a bounded range
* Use the `id` from the response as the input to the [Expense Details API](/apis/expense-details) for full expense information
* The API returns at most 100 expenses per call regardless of the `limit` value
* Fetch the available tag slugs from the [Tag List API](/apis/tag-list) and their dropdown values from the [Tag Detail API](/apis/tag-detail) before building `tag[<tagSlug>]` filters
* For `DROPDOWN` tags, prefer filtering by the tag value id — it is stable even if the value text is later renamed
* URL-encode the brackets in `tag[<tagSlug>]` (`tag%5Bcost-center%5D`) if your HTTP client does not do it for you
* Use the `tags` object in the response to confirm which tag values matched and to build follow-up filters
* Access is limited to users with expense read permission and an admin or bookkeeper role
