Skip to content
Last updated

Find and report on transactions

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.

Read one transaction

Response

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_type has a real value here. On the create response it is always UNKNOWN, because the processor does not report it on the authorization.
  • is_settled and batch_id are current, rather than frozen at the moment of the request.
  • initiator comes back null on this endpoint. That is a known gateway defect, not a change of meaning — trust the create response for it.

Search transactions

The filters:

ParameterNotes
limitPage size, default 100
offsetRecords to skip, default 0
created.gte, created.lteISO 8601, UTC, inclusive
resultAPPROVED, DECLINED, ERROR
typeComma-separated list, case-insensitive. Read the caveats below
card_typeCREDIT, DEBIT, UNKNOWN. Comma-separated list
integrationTSYS or VERICHECK — uppercase here
client_idFor a reseller reading one merchant
batch_idEverything in one batch
is_settledBoolean
sort_byCREATED, TYPE, RESULT. Default CREATED
sort_orderASC, DESC. Default DESC

Three filters that will mislead you

A 200 is not proof a filter worked. These three are worth knowing before you build a reconciliation process on them.

  • type=PAYOUT is accepted and then ignored. You get an unfiltered list with a 200, not an error. Filter payouts out in your own code.
  • type=VOID returns a server error. A voided payment is reported as CANCEL. Filter on CANCEL.
  • card_type is usually UNKNOWN. Filtering on CREDIT or DEBIT alone quietly drops most rows. Include UNKNOWN unless 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.

Paging

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.

Finding ACH returns

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.

Next steps