# Retrieving transactions

Use referenceId to prevent duplicate transaction requests and resolve uncertain outcomes.

The API provides transaction retrieval capabilities that allow you to query and check the status of transactions when processing errors occur. This is essential for handling scenarios where:

* API responses are not received due to network timeouts
* Webhooks fail to deliver
* A transaction returns an `Interrupted` status, indicating an unknown final state

When you call the `GET /transactions` (List Transactions) endpoint, the API returns a paginated list of transactions for your account, such as sales, authorizations, token operations, and so on. The endpoint supports comprehensive filtering and sorting options to help you locate specific transactions or identify processing issues. When you already hold a transaction ID, `GET /transactions/{id}` returns that one transaction directly.

> **Important:**
>
> When a transaction request times out or returns `Interrupted`, the transaction may already have succeeded. Look it up before retrying, and keep the same `referenceId` for that operation.

## Preventing duplicate requests

Use `referenceId` to prevent duplicate transaction requests. The API enforces uniqueness per merchant: once a request has been recorded, another request with the same reference is rejected. This provides duplicate prevention for an idempotent integration. The API returns an error for a duplicate reference; it does not replay the earlier response.

Choose one reference per operation and save it before sending the request. Keep that reference for any retry of the same operation. Use a new reference for each separate operation. For a request that acts on an earlier transaction, `originalReferenceId` identifies that earlier transaction; `referenceId` identifies the new operation.

If you omit `referenceId`, the API generates one. Sending your own lets you retrieve the transaction even if you never receive the response. After a timeout, `Interrupted` result, or duplicate-reference error, resolve the existing request as described below. Do not generate a new reference to bypass a duplicate-reference error, because that can execute the operation again.

## Resolving an uncertain outcome

The reliable way to find a transaction you are not sure about is by the `referenceId` you sent on the original request - which is why it is worth always sending one.

## Step 1: Send a referenceId on every request

Save a unique reference for the operation before sending it, so you can look the transaction up later without having captured the response. Keep the same value for any retry of that operation.

## Step 2: Query by that reference

```http
GET /transactions?filters=referenceId==ref_238832ae
```

## Step 3: Branch on what you find

An empty list does not prove that the request failed: a transaction request can still be in flight before a transaction record is available. This also means a duplicate-reference error can occur before the transaction appears in this list. Wait, query again, and check configured webhooks. If the outcome remains unknown, contact support before submitting another transaction request.

When you find a transaction, inspect `status`, `resultCode`, and `transactionResponses[].responseCode` (see [Transaction response codes](https://doura.ca/docs/get-started/errors-and-rate-limits.md#transaction-response-codes)). `Completed` includes both approvals and declines; earlier states can still be in progress.

## Getting one transaction

When you already have the transaction ID, fetch it directly instead of filtering the list:

```http
GET /transactions/trx_01JWBPE27KHY2K4J7A13ATQ786
```

The response is the same transaction object the list returns. An unknown ID, or a transaction that belongs to another merchant, returns `404`.

## Checking what can still be refunded

Sales and captures report a `refundableAmount`: the amount, in the smallest denomination of the currency, that can still be refunded against them. Read it before you offer a refund, so you never request more than the balance.

* It normally becomes available within seconds of approval.
* It is `0` once the transaction is fully refunded or voided.
* An ACH [chargeback](https://doura.ca/docs/payments/ach.md#chargebacks) reduces it like a refund, to `0` for a full chargeback.
* It is absent on authorizations, refunds, voids, and declined transactions. It can also be absent briefly after a sale or capture is approved. Absence does not mean unlimited: it means the value is not available yet, or does not apply.

A refund response carries its own `refundableAmount`: the balance that remains on the original transaction after that refund. When the gateway declines the refund, it equals the balance before the attempt.

### Partial refunds and retries

To request a partial refund, send `POST /transactions/refund` with an explicit `amount` no greater than the original sale or capture's `refundableAmount`. After a partial refund or a chargeback, you must supply an explicit amount for each further refund.

A refund over the limit is rejected with HTTP `400`, error code `2000`, and the message `Refund request is invalid`. `errorDetails[0].message` gives the requested amount and the available balance, which can be negative when a chargeback followed earlier refunds.

For example, a settled sale has reference `ref_238832ae` and `refundableAmount: 1000` ($10.00 for USD). Request a $3.00 partial refund with a separate reference:

```json
{
  "originalReferenceId": "ref_238832ae",
  "referenceId": "ref_refund_238832ae_1",
  "amount": 300
}
```

If approved, the refund response reports `refundableAmount: 700`. If the response is lost, query `GET /transactions?filters=referenceId==ref_refund_238832ae_1` to resolve this refund. Keep `ref_refund_238832ae_1` for any retry of the same refund. A separate partial refund uses a new reference, such as `ref_refund_238832ae_2`, while still pointing to `ref_238832ae` as the original.

The refundable balance limits the amount you can return; it does not identify whether a particular refund already succeeded. Use the refund's reference to resolve that outcome before requesting another refund.

## Filtering and sorting

Available fields for both `filters` and `sorts`: `id`, `timestamp`, `referenceId`, `orderNumber`, `invoiceNumber`, `type`, `amount`, `status`.

`type` is one of `Sale`, `Auth`, `Capture`, `Refund`, `Void`, or `Chargeback`. Treat the list as open and ignore a type you do not recognize.

```http
GET /transactions?filters=timestamp>=2025-05-21T01:00:00,type==Sale|Capture&sorts=-timestamp,type
```

Use `|` for OR conditions within a field, and a `-` prefix on a sort field for descending order. See [Request conventions](https://doura.ca/docs/get-started/conventions.md#filtering-sorting-and-paging) for the full syntax, including paging.

## Also useful for

* **Tracking an** [**ACH**](https://doura.ca/docs/payments/ach.md) **transfer** through `Processing` and `AwaitingSettlement` to completion, without waiting for the webhook.
* **Finding a sale's** [**chargeback or resubmissions**](https://doura.ca/docs/payments/ach.md#chargebacks-and-resubmissions) - their `referenceId` starts with the sale's reference, so `?filters=referenceId_=ref_238832ae-` lists them. `originalTransactionId` on each one confirms the link; it cannot be used as a filter.
* **Reconciling a settlement line** back to its transaction - a settled transaction reports a `transactionId`, which you can look up with `?filters=id==trx_...`. See [Settlements](https://doura.ca/docs/settlement-reporting/settlements.md).
