Two endpoints. GET /v1/transactions/{id} reads one; GET /v1/transactions searches. Both return the same transaction object you got when you created it.
Because there are no webhooks, these are also how you learn about anything that happens after the response: settlement, and ACH returns.
The sale from SaleWithCardResponseExample, read back after the processor reported the card type. Everything else is unchanged; the one difference is payment_method.card_type, which was UNKNOWN on the transaction response and is CREDIT here. See TransactionResponse for why the two differ.
{ "id": "TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC", "reference_transaction_id": null, "type": "SALE", "result": "APPROVED", "client_id": "CLIENT-01KFDKXMQ637EKEAY410MSQSXB", "client_dba": "Acme Jewelry", "integrations": [ "TSYS" ], "response_code": "00", "response_description": "Approved", "batch_id": "BATCH-01KEW32V6YNV11T33XGDR7TGWC", "is_settled": false, "time_created": "2026-07-15T14:22:05Z", "amount": 10000, "tip": 0, "currency": "USD", "payment_method": { "type": "CARD", "truncated_pan": "****-****-****-5439", "payment_token": "PAYMENT_TOKEN-01KFDKXMQ637EKEAY410MSQSXB", "expiry": { … }, "first_name": "John", "last_name": "Doe", "entry_method": "keyed", "auth_code": "123456", "retrieval_reference_number": "000000603076", "card_type": "CREDIT", "card_brand": "Visa", "cvv_result_code": "M", "avs_result_code": "Y", "avs_response": "Exact Match - Street address and postal code match" }, "initiator": "CUSTOMER", "network_transaction_id": "MCC1234567890", "metadata": { "order_id": "ORD-10432", "sales_channel": "web", "customer_reference": "cust-8891" } }
A reporting read is not identical to the create response, and the differences are deliberate:
card_typehas a real value here. On the create response it is alwaysUNKNOWN, because the processor does not report it on the authorization.is_settledandbatch_idare current, rather than frozen at the moment of the request.initiatorcomes back null on this endpoint. That is a known gateway defect, not a change of meaning — trust the create response for it.
The filters:
| Parameter | Notes |
|---|---|
limit | Page size, default 100 |
offset | Records to skip, default 0 |
created.gte, created.lte | ISO 8601, UTC, inclusive |
result | APPROVED, DECLINED, ERROR |
type | Comma-separated list, case-insensitive. Read the caveats below |
card_type | CREDIT, DEBIT, UNKNOWN. Comma-separated list |
integration | TSYS or VERICHECK — uppercase here |
client_id | For a reseller reading one merchant |
batch_id | Everything in one batch |
is_settled | Boolean |
sort_by | CREATED, TYPE, RESULT. Default CREATED |
sort_order | ASC, DESC. Default DESC |
A 200 is not proof a filter worked. These three are worth knowing before you build a reconciliation process on them.
type=PAYOUTis accepted and then ignored. You get an unfiltered list with a200, not an error. Filter payouts out in your own code.type=VOIDreturns a server error. A voided payment is reported asCANCEL. Filter onCANCEL.card_typeis usuallyUNKNOWN. Filtering onCREDITorDEBITalone quietly drops most rows. IncludeUNKNOWNunless you specifically want the determined ones:card_type=CREDIT,DEBIT,UNKNOWN.
The valid type values are the response vocabulary, not the create one: SALE, AUTH, INCREMENTAL_AUTH, PAYOUT, REFUND, CANCEL, CAPTURE.
The response wraps the results:
{
"total_count": 42,
"limit": 100,
"offset": 20,
"has_more": true,
"transactions": [ ... ]
}Page by incrementing offset by limit while has_more is true.
Offset paging shifts when new transactions arrive mid-walk, and the default sort is newest first, so a long-running export can see a row twice or miss one. Pin the window with created.lte before you start paging, and the set stops moving under you.
A return arrives days after approval and nothing tells you. Poll for it.
Query the window you care about and check is_returned on each transaction. Remember that return_code and return_reason are omitted rather than null when there has been no return, so read them defensively.