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:
lastfor 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:
| Field | Description |
|---|---|
bookingDate | When the PSP booked the transaction. Always set. |
valueDate | When the transaction value-dates against the merchant's balance, where the PSP provides one. See the note below. |
gross / net / fee | The transaction's amounts — see Gross and Fees. |
isBalanceRelevant | Whether the transaction moves the merchant's balance — see Gross and Fees. |
paymentClassification | PayData's normalized category for the transaction — see Classification. |
transactionType | The PSP's own, unnormalized type/description for the transaction. For logging/debugging — branch your integration logic on paymentClassification instead, not this. |
orderNumber | Merchant/shop order number, where the PSP provides one. |
receiptNumber | Receipt/invoice number, where the PSP provides one. |
bookingText | Free-text description of the booking, as it appears on the PSP's own statement. |
shopper | Information 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 / lastModifiedAt | When PayData created/last modified this record — see Changing transactions. |
reportId | The report this transaction was imported as part of, for report-based account types; null otherwise. |
fields | Account-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 nullThe 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.
paymentClassification | Meaning |
|---|---|
Payment | A regular incoming payment from the payer to the merchant. |
Purchase | Same general meaning as Payment; some connectors (e.g. PayPal) allow the merchant to use the balance for purchases. |
Refund | Money returned to the payer for a previous payment. |
PurchaseRefund | A refund of a Purchase. |
Chargeback | A payment forcibly reversed by the payer's card issuer/bank — a dispute outside the merchant's or PayData's control. |
ServiceFee | A fee charged by the payment provider itself. |
ServiceFeeRefund | A refund of a ServiceFee |
Transfer | A movement of funds that isn't a customer payment (e.g. between provider-side accounts or balances). |
Payout | A payout of accumulated balance from the provider to the merchant's bank account. |
TemporaryHold | Funds held by the provider, not yet available for payout. |
Review | Held pending a provider-side review (e.g. fraud check) before it clears. |
Reserve | Funds withheld and released by the provider as a rolling security reserve. |
CurrencyConversion | A currency conversion booking. |
CreditRepayment | Repayment of a credit or advance the provider extended to the merchant. |
Tax | A tax booking (e.g. VAT withheld or remitted by the provider). |
Adjustment | A provider-side correction that doesn't fit another category. |
Donation | A donation payment, for providers/account types that support them. |
Unknown / Unclassified | PayData 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. |
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 benullfor fee-only transactions likeServiceFee.fee— the provider's fee for this transaction, represented as a negative value. Can benullfor 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"
}
}
grossandnetare equal andfeeisnull— 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.valueDateis the0001-01-01placeholder value described above — Mollie didn't provide one for this transaction.shopperis present, since this transaction has a payer.fieldsmirrors several top-level values (orderNumber,bookingText,transactionId) under account-type-specific names, plus adds fields with no top-level equivalent (transactionStatus,paymentType) — see thefieldsrow above for whyfieldsis 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"
}
}
grossandnetare bothnullhere — onlyfeeis set, for a one-cent rounding correction on a settlement. This is the "fee-only transaction" casegrossbeing nullable (above) refers to.- No
orderNumber,receiptNumber, orshopper— 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.