# Transactions V1 — Developer Guide

> **Reference:** [Transactions (V1) Endpoint Documentation](https://papidocs.hs1api.com/publicapi/api-financial-management/transactions-(v1))


The base `/v1/transactions` endpoint provides a unified read-only view across **all transaction types** in the patient ledger. It returns the full transaction model regardless of sub-type (adjustments, insurance payments, patient payments, procedure charges).

For sub-type-specific **read** endpoints (bulk list and get-by-id), see:

- [Adjustment Transactions V1](/publicapi/endpoints/transactions-adjustments-v1)
- [Insurance Payment Transactions V1](/publicapi/endpoints/transactions-insurancepayments-v1)
- [Patient Payment Transactions V1](/publicapi/endpoints/transactions-patientpayments-v1)
- [Patient Procedure Transactions V1](/publicapi/endpoints/transactions-procedures-v1)


## GET — Bulk List Transactions

Returns a paginated list of transaction entries across all ledger types, filtered by the provided criteria.

> **⚠️ Rate Limited:** This endpoint is rate limited. See the [rate limiting guide](https://papidocs.hs1api.com/publicapi/api-consumer-guide#rate-limiting) for details.


### Parameters

| Parameter | In | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `Organization-ID` | header | Yes | string | The organization ID |
| `filter` | query | Yes | string | Filter criteria (see filter keys below) |
| `responseFields` | query | No | string | Comma-delimited list of fields to include, or `ALL` |
| `page` | query | No | string | Page number for pagination |
| `pageSize` | query | No | string | Number of records per page |
| `lastId` | query | No | string | Largest transaction ID from the previous page, used for efficient date-filter pagination |


### Filter Keys

Filters use the form `?filter=key==value` or `?filter=key>=value`. Multiple filters are comma-delimited.

| Filter Key | Operators | Example |
|  --- | --- | --- |
| `id` | `->` | `?filter=id->[123,124]` |
| `ledgerType` | `==`, `!=` | `?filter=ledgerType==InsurancePayment` |
| `patient.id` | `==`, `->` | `?filter=patient.id==789` |
| `provider.id` | `==` | `?filter=provider.id==456` |
| `transactionDate` | `>`, `<`, `>=`, `<=` | `?filter=transactionDate>=2025-01-01` |
| `location.id` | `==`, `!=`, `->` | `?filter=location.id==123` or `?filter=location.id==ALL` |
| `lastModified` | `>`, `<`, `>=`, `<=` | `?filter=lastModified>=2025-01-01` |


> **Important:** A valid filter is required on every request. If no date-limiting filter is provided, one will be automatically applied using `transactionDate >= <1 year ago>` (or the organization's creation date if more recent). Use `lastId` (not `page`) when paginating over date-filtered results for best performance.


### `ledgerType` Values

| Value | Description |
|  --- | --- |
| `PatientChargeAdjustment` | A charge-based adjustment against a patient procedure |
| `PatientCreditAdjustment` | A credit applied to a patient's ledger |
| `InsuranceRefundAdjustment` | A refund adjustment from an insurance payment |
| `PatientCreditCardRefund` | A credit card refund to a patient |
| `PatientCreditCardVoid` | A void of a credit card transaction |
| `PatientProcedureLedger` | A procedure charge on the patient ledger |
| `InsurancePayment` | A payment received from an insurance carrier |
| `PatientProcedurePayment` | A payment received from a patient |


### Example Requests

Fetch all transactions for a specific patient:

```
GET /api/v1/transactions?filter=patient.id==12000006542062
```

Fetch all transactions modified since a date (across all locations):

```
GET /api/v1/transactions?filter=lastModified>=2025-01-01,location.id==ALL
```

Fetch insurance payment transactions for a location with pagination:

```
GET /api/v1/transactions?filter=ledgerType==InsurancePayment,location.id==123&pageSize=100&lastId=5000
```

## GET — Transaction by ID

Returns a single transaction entry by its ID, regardless of ledger type.

### Parameters

| Parameter | In | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `transactionId` | path | Yes | integer | The ID of the transaction |
| `Organization-ID` | header | Yes | string | The organization ID |
| `responseFields` | query | No | string | Comma-delimited list of fields to include, or `ALL` |


### Example Request

```
GET /api/v1/transactions/100000042301
```

## Response Structure

A successful `200` response returns the following top-level structure:

| Field | Type | Description |
|  --- | --- | --- |
| `data` | object | The transaction object (see below) |
| `warnings` | array | Non-fatal warnings (operation still succeeded) |
| `errors` | array | Field-level or structural errors |


For bulk responses, `data` is an array and the response also includes:

| Field | Type | Description |
|  --- | --- | --- |
| `meta.pagination` | object | Pagination metadata (`page`, `pageSize`, `total`) |


### `data` Object — Base Transaction Fields

| Field | Type | Read-Only | Description |
|  --- | --- | --- | --- |
| `id` | integer | Yes | Unique transaction ID |
| `type` | string | Yes | Always `"Transaction"` |
| `ledgerType` | string | Yes | The transaction sub-type (see `ledgerType` values above) |
| `amount` | number | No | Transaction amount in dollars |
| `ownership` | string | No | Scope: `PATIENT` or `GUARANTOR` |
| `transactionDate` | string (date) | No | The date of the transaction (`YYYY-MM-DD`) |
| `entryDate` | string (date-time) | Yes | Timestamp when the record was created |
| `lastModified` | string (date-time) | Yes | Timestamp of the last modification |
| `isAutomaticallyPosted` | boolean | Yes | Whether the transaction was auto-posted by the system |
| `isActive` | boolean | Yes | Whether the transaction is active (not cancelled/replaced) |
| `isPartialPayment` | boolean | Yes | Whether this is a partial payment |
| `note` | string | No | Free-text note, max 255 characters |
| `metBasic` | number | No | Deductible met — basic |
| `metPreventive` | number | No | Deductible met — preventive |
| `metMajor` | number | No | Deductible met — major |
| `metOrtho` | number | No | Deductible met — ortho |
| `previousTransaction` | object | Yes | Linked model ref if this replaced a prior transaction |
| `replacedByTransaction` | object | Yes | Linked model ref if this was replaced by a later transaction |
| `patient` | object | — | Linked patient (`{ id }`) |
| `location` | object | — | Linked location (`{ id }`) |
| `provider` | object | — | Linked provider (`{ id }`) |
| `organizationLedgerType` | object | — | Linked org ledger type (`{ id }`) |
| `patientProcedure` | object | Yes | Linked procedure (`{ id }`) |
| `insuranceClaim` | object | Yes | Linked insurance claim (`{ id }`) |
| `insurancePayment` | object | Yes | Linked insurance payment (`{ id }`) |
| `transactionTags` | object | — | Map of `{ orderIndex: { id } }` tag references |
| `reasonTags` | object | — | Map of `{ orderIndex: { id } }` transfer reason references |
| `patientPaymentBilling` | object | — | Billing details (`checkNumber`, `bankNumber`, `referenceNumber`) |
| `distributions` | array | — | Allocation records (`chargeId`, `appliedAmount`, `isActive`) |


## Streaming

The transactions domain is streamable via the [Streaming API](https://papidocs.hs1api.com/publicapi/api-consumer-guide#streaming). Events are published whenever transaction records are created, updated, or deleted.

All transaction sub-types (adjustments, insurance payments, patient payments, procedures) share the same domain type in the routing key: **`TransactionV1`**.

### Routing Key Format

```
organizationId.locationId.TransactionV1.operationType
```

| Segment | Description |
|  --- | --- |
| `organizationId` | Your organization's ID |
| `locationId` | A specific location ID, or `*` for all locations |
| `TransactionV1` | The domain type for all transaction records |
| `operationType` | `CREATE`, `UPDATE`, `DELETE`, or `*` for all |


### Example Routing Keys

Listen for all transaction events across all locations:

```
66d22762060811049b50d085.*.TransactionV1.*
```

Listen for creates only at a specific location:

```
66d22762060811049b50d085.1000000000123.TransactionV1.CREATE
```

### Operations by Sub-Type

| Sub-Type | `CREATE` | `UPDATE` | `DELETE` |
|  --- | --- | --- | --- |
| Adjustment (`PatientChargeAdjustment`) | Yes | Yes | No |
| Adjustment (`PatientCreditAdjustment`) | Yes | Yes | Yes |
| Insurance Payment | Yes | Yes (emitted as `CREATE` on the rebill record) | No |
| Patient Payment | Yes | Yes (emitted as `CREATE` on the rebill record) | No |
| Procedure | Yes | No | Yes |


> **Note on corrections (rebills):** When an insurance payment or patient payment is corrected, a new replacement record is created rather than the original being modified. The stream emits a `CREATE` event for the new record. The original record is cancelled (`isActive: false`) but does not emit a `DELETE` event.


> **Filtering by `ledgerType`:** Since all sub-types share the `TransactionV1` domain, use the `ledgerType` field in the event payload to distinguish between sub-types in your consumer.


## Errors & Warnings Reference

details
summary
strong
HTTP Status Code Errors
— click to expand
#### `400` — Bad Request

The request filter or parameters are invalid or cannot be processed. A filter is required on every bulk GET request.

#### `401` — Unauthorized

|  |  |
|  --- | --- |
| **Message** | Authentication is required and has failed or has not been provided. |
| **Why** | No valid auth token was sent, the token is expired, or the token is malformed. |
| **Fix** | Provide a valid Bearer token in the `Authorization` header. |


#### `403` — Forbidden

|  |  |
|  --- | --- |
| **Message** | The request is understood, but it has been refused or access is not allowed. |
| **Why** | The caller is not permitted to read transactions for this organization. |
| **Fix** | Confirm credentials and organization access with your integration administrator. |


#### `404` — Not Found

|  |  |
|  --- | --- |
| **Message** | The requested resource is either missing or does not exist. |
| **Why** | No transaction exists for the given ID within your organization. |
| **Fix** | Confirm the `transactionId` is correct and belongs to your organization. |


#### `408` — Request Timeout

|  |  |
|  --- | --- |
| **Message** | The server timed out while processing the request. |
| **Why** | The server took too long to respond, often due to high server load or an overly broad filter. |
| **Fix** | Narrow your filter criteria and retry. If the issue persists, contact support. |


#### `429` — Too Many Requests

|  |  |
|  --- | --- |
| **Message** | Rate limit exceeded. |
| **Why** | Your client has made too many requests in a short period of time. |
| **Fix** | Implement exponential backoff and retry logic. See the [rate limiting guide](https://papidocs.hs1api.com/publicapi/api-consumer-guide#rate-limiting). |


#### `500` — Internal Server Error

|  |  |
|  --- | --- |
| **Message** | An unexpected error occurred. |
| **Why** | An unhandled server-side error occurred. |
| **Fix** | Retry the request. If the issue persists, contact support with the request details and timestamp. |


details
summary
strong
Field-Level Validation Errors
— click to collapse
These errors are returned in the `errors` array alongside a `400` status code.

### `filter`

**Error:** Missing or invalid filter.

|  |  |
|  --- | --- |
| **Why** | The `filter` parameter was omitted, left empty, or used an unsupported key or operator. |
| **Fix** | Provide at least one valid filter key and value, e.g. `?filter=lastModified>=2025-01-01`. |


### `ledgerType`

**Error:** Invalid value for `ledgerType` filter.

|  |  |
|  --- | --- |
| **Why** | The `ledgerType` value is not one of the recognized enum values. |
| **Fix** | Use one of: `PatientChargeAdjustment`, `PatientCreditAdjustment`, `InsuranceRefundAdjustment`, `PatientCreditCardRefund`, `PatientCreditCardVoid`, `PatientProcedureLedger`, `InsurancePayment`, `PatientProcedurePayment`. |