Retrieving Transactions

Read transactions from your backend with the REST API, or inside your app with the SDK. Use the backend for reporting, reconciliation, and anything that spans merchants. Use the SDK for the signed-in merchant's own history screen.

Every method returns the same transaction object. The Transaction Result explains its fields.

Choose a Method

You need Use
A filtered, sorted, paged list GET /v2/transactions
One transaction with its history GET /v1/transactions/{transaction_id}
The result of one operation whose event ID you saved GET /v1/transactions/event/{event_id}
The signed-in merchant's history inside your app The SDK history methods in Show Transactions in Your App

Call the REST endpoints from your backend with an API key that holds payments:read. A key sees its own account and the accounts beneath it.

GET /v2/transactions returns one page of transactions, newest first unless you sort otherwise. Every filter is optional. Filters combine with AND, and a filter you repeat matches any of its values.

curl --get 'https://api.uat.koard.com/v2/transactions' \
  -H 'X-Koard-apikey: YOUR_API_KEY' \
  --data-urlencode 'account_id=YOUR_MERCHANT_ACCOUNT_ID' \
  --data-urlencode 'status=captured' \
  --data-urlencode 'status=settled' \
  --data-urlencode 'start_date=1767225600000' \
  --data-urlencode 'sort_by=created_at' \
  --data-urlencode 'sort_order=desc' \
  --data-urlencode 'limit=50' \
  --data-urlencode 'offset=0'

The response wraps the page in a paging envelope. This example is abridged.

{
  "transactions": [
    {
      "transaction_id": "YOUR_TRANSACTION_ID",
      "event_id": "YOUR_EVENT_ID",
      "status": "captured",
      "status_reason": "approved",
      "transaction_type": "sale",
      "currency": "USD",
      "subtotal": 1000,
      "tax_amount": 85,
      "tip_amount": 200,
      "total_amount": 1285,
      "card": "****1234",
      "card_brand": "Visa",
      "created_at": 1767229200000
    }
  ],
  "total": 132,
  "limit": 50,
  "offset": 0,
  "page": 1
}

Filters

Filter Matches
account_id Transactions of a merchant account, or of every merchant beneath a partner or PSP account. Repeatable.
status One or more status values. Repeatable.
transaction_type One or more operations: sale, auth, capture, refund, reverse, tip_adjust, incremental_auth, or manually_keyed_sale. Repeatable.
location_id, terminal_id, batch_id The location, terminal, or settlement batch.
start_date, end_date A created_at range in milliseconds since the Unix epoch.
min_amount, max_amount A total_amount range in minor currency units.
transaction_id, event_id, gateway_transaction_id An exact identifier.
card_number Part of the masked card number, such as the last four digits.
search_term Free text across common fields.
device_type iphone, ipad, android_phone, android_tablet, other, or unknown for transactions recorded without a device family.
payment_method, card_brand The exact label stored on the transaction. Labels differ by processor, so read the value from a transaction before you filter on it.
processor_mid, processor_tid Part of the processor merchant ID or terminal ID.
reader_identifier, owner_id The reader that took the tap, or the owner account, usually the parent PSP or partner.

Sorting

Parameter Values Default
sort_by created_at, total_amount, transaction_id, status, card_brand created_at
sort_order asc, desc desc

Paging

Parameter Meaning Default Maximum
limit Transactions per page 50 200
offset Transactions to skip 0 None

Read total from the first page, then raise offset by limit until offset + transactions.length reaches total. Keep the filters and sort the same for every page. Pagination lists the page sizes of the other list endpoints.

Get One Transaction

curl 'https://api.uat.koard.com/v1/transactions/YOUR_TRANSACTION_ID' \
  -H 'X-Koard-apikey: YOUR_API_KEY'

The response is the transaction with its history of earlier events. A transaction that does not exist and one that your key cannot see both return 404.

When a payment response was lost, look the operation up by the event ID you saved before you sent it: GET /v1/transactions/event/{event_id}. A 404 there does not prove that the payment never reached the processor. Follow Idempotency and Outcome Recovery before you retry.

Show Transactions in Your App

For the signed-in merchant's own history, call the SDK from the app.

Platform Methods
Android getTransactions(limit, offset) and getTransaction(transactionId). See Transaction history and receipts.
iOS transactionHistory(), transactionsByStatus(...), searchTransactions(...), and searchTransactionsAdvanced(...). See Running Payments.

For history that spans merchants, or filters the SDK does not offer, have your backend call GET /v2/transactions and return the rows your screen needs. Do not ship a backend key in the app.

What to Show

In a list row From
Amount total_amount in minor units, formatted with currency. On a refund row this is the refund event's total, not the original payment.
Status status, mapped to your own label
Card card_brand and the last four digits of card
Time created_at, converted from milliseconds to the device's local time

In a detail view, add the breakdown (subtotal, tax_amount, tip_amount, surcharge_amount), the refunded and reversed totals, the processor response, and the history of events.

Refunded Payments

A list row is the latest event on a payment. After a refund, that event is the refund itself. Its transaction_type is refund, and its total_amount and breakdown describe that event, not the original payment. What total_amount holds on a refund event differs by processor, so never use it as the payment's amount.

refunded is the cumulative amount returned across every refund of the payment. A refunded total above zero means some of the payment was returned, whatever the current status.

To show whether a refund is partial or full, read the payment's own amount from the detail view. GET /v1/transactions/{transaction_id} returns the earlier events in history, newest first. Take total_amount from the newest event that is not a refund or a reversal, and compare the cumulative refunded total with it. Do not compare refunded with the refund event's own total_amount. Refund describes the fields of a refund event.

Map each status to a label the operator understands. A preauth that is authorized is a hold, not a completed sale.

Status Suggested label
captured, settled Paid
authorized On hold, not captured yet
pending, surcharge_pending In progress
declined Declined
error Needs review
refunded Refunded. See Refunded Payments to show a partial refund.
reversed Reversed
canceled Canceled

This example turns one transaction from the API into a row for a history screen.

type TransactionRow = {
  id: string;
  amount: string;
  status: string;
  card: string;
  time: string;
};

const STATUS_LABELS: Record<string, string> = {
  captured: "Paid",
  settled: "Paid",
  authorized: "On hold",
  pending: "In progress",
  surcharge_pending: "In progress",
  declined: "Declined",
  error: "Needs review",
  refunded: "Refunded",
  reversed: "Reversed",
  canceled: "Canceled",
};

// Amounts are integers in minor units. The number of decimal places
// depends on the currency, so do not divide by a fixed 100.
function formatMinor(amount: number, currency: string): string {
  const formatter = new Intl.NumberFormat(undefined, { style: "currency", currency });
  const digits = formatter.resolvedOptions().maximumFractionDigits ?? 2;
  return formatter.format(amount / 10 ** digits);
}

function toRow(transaction: any): TransactionRow {
  return {
    id: transaction.transaction_id,
    // On a refund row this is the refund event's total, not the original payment.
    amount: formatMinor(transaction.total_amount, transaction.currency),
    status: STATUS_LABELS[transaction.status] ?? "Unknown",
    card: `${transaction.card_brand} ${transaction.card.slice(-4)}`,
    time: new Date(transaction.created_at).toLocaleString(),
  };
}

In the detail view, work out the refund state from the original payment, not from the refund event. Pass the result of GET /v1/transactions/{transaction_id}.

type RefundState = "none" | "partial" | "full" | "unknown";

function refundState(transaction: any): RefundState {
  const refunded = transaction.refunded ?? 0;
  if (refunded <= 0) return "none";

  // The current event comes first, then history from newest to oldest.
  const events = [transaction, ...(transaction.history ?? [])];
  const payment = events.find(
    (event: any) =>
      !["refund", "reverse"].includes(event.transaction_type) &&
      ["authorized", "captured", "settled"].includes(event.status),
  );
  if (!payment) return "unknown";

  return refunded < payment.total_amount ? "partial" : "full";
}

Keep transaction_id on each row so a tap opens the detail view, and so capture, tip adjust, reverse, and refund act on the right payment.

See Also