Skip to main content

Transactions

After an account is created, PayData starts fetching transactions from the payment provider. Depending on the account type and the amount of transactions, this process can take from a few seconds up to hours.

Reading transactions

Once transactions are available for the account they can be obtained with

  • the GetTransactions method. The method returns all transactions, that have been downloaded from the payment provider ordered by the PayData creation timestamp.

Before calling the GetTransactions method it is useful to call the GetAccount method to determine whether there are any new transactions available. It returns the elementStatistics object with

  • the number of transactions: count;
  • the date of the first transaction: first;
  • and the date of the last transaction: last for the account.

In some cases, it can be necessary to re-read transactions from a payment provider for a particular period of time. It can be done with

  • the TriggerAccountRefresh method. The method tells PayData to re-read transactions from a payment provider, starting from the specified date.

Interpreting transactions

A transaction has more fields than are obvious at a glance — see the examples below for what a full response looks like. The identifier-shaped fields (id, transactionId, fields.uniqueId) are covered separately in Transaction Identifiers; the rest:

FieldDescription
bookingDateWhen the PSP booked the transaction. Always set.
valueDateWhen the transaction value-dates against the merchant's balance, where the PSP provides one. See the note below.
gross / net / feeThe transaction's amounts — see Gross and Fees.
isBalanceRelevantWhether the transaction moves the merchant's balance — see Gross and Fees.
paymentClassificationPayData's normalized category for the transaction — see Classification.
transactionTypeThe PSP's own, unnormalized type/description for the transaction. For logging/debugging — branch your integration logic on paymentClassification instead, not this.
orderNumberMerchant/shop order number, where the PSP provides one.
receiptNumberReceipt/invoice number, where the PSP provides one.
bookingTextFree-text description of the booking, as it appears on the PSP's own statement.
shopperInformation about the payer, where the PSP provides it: name, email, username, identifier. Not present on transactions with no associated payer (e.g. most Adjustment entries).
createdAt / lastModifiedAtWhen PayData created/last modified this record — see Changing transactions.
reportIdThe report this transaction was imported as part of, for report-based account types; null otherwise.
fieldsAccount-type-specific fields, documented per account type — see account fields. Field names generally follow the PSP's own naming rather than a fixed PayData schema.
valueDate can be a placeholder value instead of null

The schema marks valueDate as nullable, but for some connectors, no value date is not sent as null — instead you may see the placeholder value 0001-01-01T00:00:00.0000000Z (see the second example below). If you see exactly this value, treat it the same as null: there is no value date, not a real date of 0001-01-01.

Classification

Every transaction has a paymentClassification, a normalized category PayData assigns regardless of the payment provider — use it to reason about a transaction's business meaning without writing separate logic per PSP. The provider's own, unnormalized type string (if it has one) is available separately as transactionType, for logging/debugging rather than as something to branch your integration logic on.

paymentClassificationMeaning
PaymentA regular incoming payment from the payer to the merchant.
PurchaseSame general meaning as Payment; some connectors (e.g. PayPal) allow the merchant to use the balance for purchases.
RefundMoney returned to the payer for a previous payment.
PurchaseRefundA refund of a Purchase.
ChargebackA payment forcibly reversed by the payer's card issuer/bank — a dispute outside the merchant's or PayData's control.
ServiceFeeA fee charged by the payment provider itself.
ServiceFeeRefundA refund of a ServiceFee
TransferA movement of funds that isn't a customer payment (e.g. between provider-side accounts or balances).
PayoutA payout of accumulated balance from the provider to the merchant's bank account.
TemporaryHoldFunds held by the provider, not yet available for payout.
ReviewHeld pending a provider-side review (e.g. fraud check) before it clears.
ReserveFunds withheld and released by the provider as a rolling security reserve.
CurrencyConversionA currency conversion booking.
CreditRepaymentRepayment of a credit or advance the provider extended to the merchant.
TaxA tax booking (e.g. VAT withheld or remitted by the provider).
AdjustmentA provider-side correction that doesn't fit another category.
DonationA donation payment, for providers/account types that support them.
Unknown / UnclassifiedPayData could not determine a classification for this transaction; treat both the same way — as "needs its own handling or manual review" — rather than assuming they're equivalent to any other category.
note

This list categorizes transactions using standard payment-industry terms, kept intentionally succinct rather than split into many overlapping categories.

Handle unrecognized values gracefully in your code — new categories can appear as PSPs or regulations change.

Gross and Fees

Transactions carry up to three amounts, each an {currency, value} object:

  • gross — the full amount before any provider fee is deducted. Can be null for fee-only transactions like ServiceFee.
  • fee — the provider's fee for this transaction, represented as a negative value. Can be null for transactions without fees like money transfers (Payout / Transfer).
  • net — the amount actually settled: net = gross + fee.

isBalanceRelevant tells you whether the transaction actually moves the merchant's balance with the provider; use it to distinguish informational entries from ones you should reconcile against a payout. isBalanceRelevant: false transactions can generally be ignored and serve informational purposes. E.g. some PSPs report non-balance-relevant credit-card authorization transactions.

Examples

Two real (sandbox) transactions from a Mollie-backed account, showing how differently a transaction can be populated depending on what it represents.

A card payment

{
"id": "w6je7aev5r",
"bookingDate": "2024-06-14T10:14:36.0000000Z",
"valueDate": "0001-01-01T00:00:00.0000000Z",
"gross": { "currency": "EUR", "value": 12.5 },
"net": { "currency": "EUR", "value": 12.5 },
"fee": null,
"isBalanceRelevant": true,
"paymentClassification": "Payment",
"transactionType": "Payment",
"transactionId": "tr_WGLigpRYmm",
"orderNumber": "61",
"bookingText": "Bestellung 61",
"shopper": {
"name": "NetConnections GmbH",
"identifier": "cst_EwYaqyqjYL"
},
"createdAt": "2024-11-27T14:16:45.6158051Z",
"lastModifiedAt": "2024-11-27T14:16:45.6158052Z",
"reportId": "k9gsec8kktm",
"fields": {
"uniqueId": "tr_WGLigpRYmm",
"customerName": "NetConnections GmbH",
"orderId": "61",
"transactionId": "tr_WGLigpRYmm",
"customerId": "cst_EwYaqyqjYL",
"reference3": "stl_oyk5p4",
"transactionStatus": "paid",
"transactionDescription": "Bestellung 61",
"paymentType": "creditcard",
"orderNumber": "61",
"reference4": "paid",
"bookingText": "Bestellung 61",
"transactionType": "Payment",
"paymentMethod": "creditcard",
"payerName2": "NetConnections GmbH"
}
}
  • gross and net are equal and fee is null — Mollie doesn't break its fee out on the payment itself; see the rounding-difference example on the right for where a fee-shaped amount actually shows up instead.
  • valueDate is the 0001-01-01 placeholder value described above — Mollie didn't provide one for this transaction.
  • shopper is present, since this transaction has a payer.
  • fields mirrors several top-level values (orderNumber, bookingText, transactionId) under account-type-specific names, plus adds fields with no top-level equivalent (transactionStatus, paymentType) — see the fields row above for why fields is account-type-specific rather than fixed.

A fee-only adjustment

{
"id": "26vw7s23vr",
"bookingDate": "2024-06-21T04:09:45.0000000Z",
"valueDate": "0001-01-01T00:00:00.0000000Z",
"gross": null,
"net": null,
"fee": { "currency": "EUR", "value": -0.01 },
"isBalanceRelevant": true,
"paymentClassification": "Adjustment",
"transactionType": "RoundingDifferences",
"transactionId": "stl_oyk5p4-2024-6-1",
"bookingText": "Rounding differences",
"createdAt": "2024-11-27T14:16:45.6614429Z",
"lastModifiedAt": "2024-11-27T14:16:45.6614431Z",
"reportId": "k9gsec8kktm",
"fields": {
"uniqueId": "stl_oyk5p4-2024-6-1",
"transactionId": "stl_oyk5p4-2024-6-1",
"transactionDescription": "Rounding differences",
"paymentType": "RoundingDifferences",
"bookingText": "Rounding differences",
"transactionType": "RoundingDifferences"
}
}
  • gross and net are both null here — only fee is set, for a one-cent rounding correction on a settlement. This is the "fee-only transaction" case gross being nullable (above) refers to.
  • No orderNumber, receiptNumber, or shopper — there's no order or payer behind a settlement-level correction like this one.
  • Both transactions share the same reportId: they were imported as part of the same report.

Staying up-to-date

Re-reading every report or transaction an account has on every check does not scale. See Staying Up to Date for the recommended incremental sync approach — covering report-based accounts, non-report-based accounts, syncing via DataImports (which also catches support-case corrections a plain transactions cursor would miss), and using notifications instead of polling.

Changing transactions

Generally PayData does not change the values of transactions once imported. There are a few exceptions where PayData makes updates to keep the information in sync with the PSP — for example during a support case.

lastModifiedAt advances whenever this happens; createdAt never changes. If you need to know whether a transaction you already have was corrected, compare lastModifiedAt rather than relying on re-fetching by id. See Staying Up to Date for how syncing via DataImports surfaces these corrections automatically, without needing to re-scan every transaction you already have.