Regular Transactions Schema

Field reference for user-scoped regular transaction series detect and result messages on Kafka.

Overview

Regular transaction series detection is user-scoped: every detect and result message includes a userId, and result egress is always shaped as { userId, accounts[] }. A user may have multiple accounts (for example, a current account and a credit card).

To request detection, publish a message to the regular-transactions detect topic. A user-scoped result is then published to the regular-transactions result topic.

Detect messages may contain one account or several accounts for the same user. Moneyhub configures how daily batch detection is grouped for your environment; see List of configurable features.

This mirrors the affordability interface: one userId in, one user-scoped message out per detect message processed.

Request message

The Kafka message value must be a JSON object:

FieldTypeOptionalDescription
userIdString (max 36)NoUser identifier whose accounts are being processed.
accountsArray<Object>YesAccounts to process. Required unless the message is a dated user request (below). At least one entry is required when present.
asOfDateString (max 10)YesCalendar date (yyyy-MM-dd) the detection should end on. See Dated detection.

Each element of accounts[]:

FieldTypeOptionalDescription
accountIdString (max 36)NoAccount identifier to detect series for.
modeString (max 11)YesDetection mode: full (default) or incremental.
updatedAtStringYesISO 8601 timestamp. Required when mode is incremental; ignored for full.

When asOfDate is omitted, full mode uses the configured retention window of transaction history. incremental mode uses transactions from updatedAt onwards and merges with the current series.

Dated detection

asOfDate asks for the series as they stood at the end of that calendar day, using the 12 months of stored transactions ending on that date. The whole of asOfDate is included. Transactions that have not already been submitted for those dates are not part of the run.

A dated message applies to every account in accounts[]. mode and updatedAt are not used. The run does not merge with the current series, and it does not replace them. A later detection or affordability request that omits asOfDate still uses the current series. Sending the same date again replaces the series stored for that date only.

You can omit accounts and send only userId and asOfDate. Detection then runs for every account already known for that user. If userId is missing, or the user has no accounts, the message is dead-lettered and nothing is stored.

When affordability after regular transactions is enabled, a successful dated detection also requests the affordability report for the same date. You can request that report yourself by publishing the same asOfDate to the affordability calculate topic. See Affordability schema.

If historical affordability functionality is disabled for your environment, any detect message that includes asOfDate is dead-lettered and nothing is read or stored. Messages that omit asOfDate are unchanged. A value that is not a real calendar date (yyyy-MM-dd) is rejected and is not treated as today. See Errors.

The message key should be a unique identifier (UUID recommended). It is copied to the corresponding result message.

Example (detect message — single account)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "accounts": [
    {
      "accountId": "090ea264-eb48-494c-9d59-1b10b322c3e1",
      "mode": "full"
    }
  ]
}

Example (detect message for a past date)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "asOfDate": "2025-04-01",
  "accounts": [
    {
      "accountId": "090ea264-eb48-494c-9d59-1b10b322c3e1",
      "mode": "full"
    }
  ]
}

Example (dated detection for every account of a user)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "asOfDate": "2025-04-01"
}

Example (detect message — multiple accounts)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "accounts": [
    {
      "accountId": "090ea264-eb48-494c-9d59-1b10b322c3e1",
      "mode": "full"
    },
    {
      "accountId": "de4be182-efb4-4aad-b221-fa29631e6653",
      "mode": "incremental",
      "updatedAt": "2026-06-01T12:00:00.000Z"
    }
  ]
}

Result topic

Detection results are published to the regular-transactions result topic. Failed messages are sent to the regular-transactions dead-letter topic; see Errors for the general dead-letter envelope shape.

Result message envelope

The Kafka message value is a JSON object:

FieldTypeOptionalDescription
userIdString (max 36)NoUser identifier that was requested for the detection run.
accountsArray<Object>NoDetection results per account (schema below). One entry per account processed.

The message key is copied from the triggering detect message when present; otherwise a new UUID is generated.

Account result (accounts[])

FieldTypeOptionalDescription
accountIdString (max 36)NoAccount identifier for which series were computed.
predictionsArray<Object>NoArray of regular transaction series objects (schema below). May be empty.

Series object (predictions[])

FieldTypeOptionalDescription
seriesIdString (max 36)NoThe ID of the regular transaction series. UUID format.
accountIdString (max 36)NoThe ID of the account the transactions belong to. Matches the parent accounts[].accountId.
userIdString (max 36)NoThe ID of the user the transactions belong to. Matches the envelope userId.
typeString (max 7)NoWhether the series contains income or payment transactions (income or payment).
subtypeString (max 21)YesSubtype: directDebit, standingOrder, frequentVisit, committedCardPayment, or other.
frequencyString (max 11)NoFrequency: yearly, quarterly, monthly, fortnightly, or weekly.
descriptionString (max 256)NoThe full description of the latest transaction in the series. Same limit as enriched transaction description.
cleanedDescriptionString (max 256)NoThe cleaned description of the latest transaction in the series.
numTxMatchedInSeriesIntegerNoThe number of transactions contained in the series.
gapLengthInFreqUnitsIntegerNoIf the series contains a gap, the number of whole frequency units that are missing.
dateAnomaliesCountIntegerNoThe number of date anomalies detected in the series.
numReturnedTxsIntegerNoThe number of returned transactions (reversed or declined) contained in the series.
lastDateString (max 10)NoThe date of the latest transaction in the series (yyyy-MM-dd).
predictedDateString (max 10)NoThe predicted date of the next transaction in the series (yyyy-MM-dd).
predictedDateEarliestString (max 10)YesThe earliest predicted date at which the next transaction could occur (null if not set).
predictedDateLatestString (max 10)YesThe latest predicted date at which the next transaction could occur (null if not set).
predictedTxLateOrNotDetectedBooleanYesWhether the next predicted transaction is overdue or not detected. May be omitted if not set.
predictedAmountNumberNoThe predicted amount of the next transaction (as emitted by detection; currency base units where applicable).
predictedAmountLowerNumberYesLower bound of the predicted amount.
predictedAmountUpperNumberYesUpper bound of the predicted amount.
currencyString (max 3)YesISO 4217 currency code. Same limit as enriched transaction currency.
counterpartyIdString (max 36)YesL3 counterparty identifier from the first matched transaction that has counterparty enrichment. UUID format.
predictedCategoryIdString (max 3)NoThe ID of the predicted category. Same limit as enriched transaction l2CategoryId.
l3CounterpartyCategoryString (max 32)YesThe counterparty analysis category identifier. Same limit as counterparty l3CounterpartyCategory. May be null.
transactionsArray<Object>NoMatched historical transactions in the series (schema below).

Transaction object (transactions[])

FieldTypeOptionalDescription
uidString (max 36)NoTransaction identifier.
dateString (max 10)NoTransaction date (yyyy-MM-dd).
descriptionString (max 256)NoTransaction description.
amountNumberNoTransaction amount.
categoryIdString (max 3)NoL2 category identifier.
cleanedDescriptionString (max 256)NoCleaned description.
txCodeString (max 64)YesProvider transaction type code.
cardPresentBooleanYesWhether the transaction was card-present.
l3CounterpartyCategoryString (max 32)YesCounterparty analysis category identifier. May be null when not available.

Example (result message body)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "accounts": [
    {
      "accountId": "090ea264-eb48-494c-9d59-1b10b322c3e1",
      "predictions": [
        {
          "seriesId": "45f004dc-254f-5d09-b07f-8d4de4487781",
          "accountId": "090ea264-eb48-494c-9d59-1b10b322c3e1",
          "userId": "550e8400-e29b-41d4-a716-446655440000",
          "type": "payment",
          "subtype": "frequentVisit",
          "frequency": "quarterly",
          "description": "Dentist Checkup",
          "cleanedDescription": "Dentist Checkup",
          "numTxMatchedInSeries": 4,
          "gapLengthInFreqUnits": 0,
          "dateAnomaliesCount": 0,
          "numReturnedTxs": 0,
          "lastDate": "2026-01-20",
          "predictedDate": "2026-04-20",
          "predictedDateEarliest": "2026-04-20",
          "predictedDateLatest": "2026-04-21",
          "predictedTxLateOrNotDetected": false,
          "predictedAmount": -65,
          "predictedAmountLower": -65,
          "predictedAmountUpper": -65,
          "currency": "GBP",
          "counterpartyId": "203d5a9a-d4dd-5ce5-ab60-60f740336dea",
          "predictedCategoryId": "11",
          "l3CounterpartyCategory": null,
          "transactions": [
            {
              "uid": "TXN-090ea264-775",
              "date": "2026-01-20",
              "description": "Dentist Checkup",
              "amount": -65,
              "categoryId": "11",
              "cleanedDescription": "Dentist Checkup",
              "txCode": null,
              "cardPresent": false,
              "l3CounterpartyCategory": null
            },
            {
              "uid": "TXN-090ea264-774",
              "date": "2025-10-20",
              "description": "Dentist Checkup",
              "amount": -65,
              "categoryId": "11",
              "cleanedDescription": "Dentist Checkup",
              "txCode": null,
              "cardPresent": false,
              "l3CounterpartyCategory": null
            }
          ]
        }
      ]
    },
    {
      "accountId": "de4be182-efb4-4aad-b221-fa29631e6653",
      "predictions": []
    }
  ]
}

Did this page help you?