Affordability Schema

Field reference for user-scoped affordability calculate and result messages on Kafka.

Overview

Affordability reports are produced per user. A user may have multiple accounts (for example, a current account and a credit card); the report aggregates enriched transactions and regular-transaction predictions across all of that user's accounts.

To request a report, publish a message to the affordability calculate topic. A corresponding result is then published to the affordability result topic.

Moneyhub can also configure regular-transaction detection to request affordability automatically after a successful run, so manual calculate publishes are not always required. See List of configurable features.

Request message

The Kafka message value must be a JSON object:

FieldTypeOptionalDescription
userIdString (max 36)NoUser identifier for whom the report is requested.

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

Example (request message)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

Result topic

Successful calculation results are published to the affordability result topic. Failed messages are sent to the affordability 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)YesUser identifier from the calculate request (present for user-scoped runs).
accountIdString (max 36)YesAccount identifier from the calculate request (present for account-scoped runs).
fullAffordabilityReportObjectNoThe affordability report (schema below).

At least one of userId or accountId is present, matching the calculate request. The message key is copied from the triggering calculate message when present; otherwise a new UUID is generated.

Report object (fullAffordabilityReport)

The report analyses up to 12 months of transaction history across accounts in scope for the request, ending on the calculation date. Amounts are plain numbers in major currency units (for example, pounds rather than pence).

Missing sections may be omitted when they are not produced for the request.

FieldTypeOptionalDescription
incomeObjectYesIncome analysis, including regular income detection.
expenditureObjectYesExpenditure medians by affordability category.
transfersObjectYesNet and outgoing transfer medians.
gamblingObjectYesGambling outflow median.
loansObjectYesOpened loan details and repayment median.
returnedPaymentsObjectYesReturned or reversed direct-debit activity.
overdraftsObjectYesOverdraft usage per account.

income

FieldTypeOptionalDescription
medianNumberYesMedian monthly income (excluding transfers).
medianIncludingTransfersNumberYesMedian monthly income including transfers.
amountConsistencyNumberYesConsistency score for income amounts (0–1).
categoriesUsedArray<Object>YesIncome category IDs referenced in the analysis.
longevityObjectYesHow long income has been observed.
primaryIncomeAccountObjectYesAccount receiving the primary income stream.
regularIncomeObjectYesWhether regular income was detected, plus predicted monthly amount.

income.categoriesUsed[]

FieldTypeOptionalDescription
uidString (max 3)NoLevel 2 category ID.
keyStringNoAffordability category key.

income.longevity

FieldTypeOptionalDescription
consecutiveIncomeObjectYesLongest run of consecutive income months.
incomePeriodLengthObjectYesTotal span of observed income.

Each longevity sub-object has a months integer field.

income.primaryIncomeAccount

FieldTypeOptionalDescription
uidString (max 36)NoAccount identifier.

income.regularIncome

FieldTypeOptionalDescription
isDetectedBooleanYesWhether regular income streams were used in monthly predictions.
predictedObjectYesAggregated regular income prediction.

income.regularIncome.predicted.monthly

FieldTypeOptionalDescription
amountNumberNoPredicted total monthly regular income.

expenditure

Each category object contains a median amount (negative for outflows).

FieldTypeOptionalDescription
cashWithdrawalsObjectYesATM and cash-withdrawal spending.
discretionaryObjectYesDiscretionary spending.
fixedObjectYesFixed commitments such as rent and loan repayments.
flexibleObjectYesFlexible non-discretionary spending.
nonDiscretionaryObjectYesEssential non-discretionary spending.

Expenditure category object

FieldTypeOptionalDescription
medianNumberNoMedian monthly spend (negative for outflows).

transfers

FieldTypeOptionalDescription
medianNumberYesMedian net monthly transfer amount.
outObjectYesOutgoing transfers.

transfers.out

FieldTypeOptionalDescription
medianNumberNoMedian monthly outgoing transfers (negative).

gambling

FieldTypeOptionalDescription
outObjectYesGambling stakes.

gambling.out

FieldTypeOptionalDescription
medianNumberNoMedian monthly gambling spend (negative).

loans

FieldTypeOptionalDescription
openedObjectYesRecently opened loans by type and period.
repaymentsObjectYesLoan repayment median.

loans.opened.details[]

One entry per loan type and loan window (30, 90, 180, and 365 days).

FieldTypeOptionalDescription
typeStringNoLoan type: dca/dmp, bnpl, unsecured, hcstc, secured, or unknown.
countIntegerNoNumber of loans opened in the period.
periodObjectNoLoan window (unit: days; value: 30, 90, 180, or 365).
totalObjectNoAggregated amounts (borrowed, repaid) in major currency units for loans opened in the period.

loans.repayments

FieldTypeOptionalDescription
medianNumberNoMedian monthly loan repayments (negative).

returnedPayments

FieldTypeOptionalDescription
countIntegerYesTotal number of returned-payment transactions in the analysis period.
periodObjectYesLength of the returned-payments analysis (months).
detailsArray<Object>YesReturned-payment counts grouped by category and period.

returnedPayments.details[]

One entry per affordability category and period (30, 90, 180, and 365 days).

FieldTypeOptionalDescription
categoryStringNoAffordability category key for the returned payments.
countIntegerNoNumber of returned payments in the period.
periodObjectNoRolling period (unit: days; value: 30, 90, 180, or 365).
totalObjectNoAggregated returned amount (returned) in major currency units.

overdrafts.usage.details[]

FieldTypeOptionalDescription
accountUidString (max 36)NoAccount identifier.
daysInOverdraftIntegerNoTotal days spent in overdraft in the last 90 days.
daysInUnarrangedOverdraftIntegerYesDays in unarranged overdraft in the last 90 days.
earliestBalanceDateStringNoEarliest balance date available for overdraft analysis (ISO 8601).
periodsInOverdraftArray<Object>NoContiguous overdraft periods in the last 90 days.

overdrafts.usage.details[].periodsInOverdraft[]

FieldTypeOptionalDescription
startString (max 10)NoPeriod start date (yyyy-MM-dd).
endString (max 10)NoPeriod end date (yyyy-MM-dd).
daysIntegerNoNumber of days in the overdraft period.
minimumBalanceNumberNoLowest balance reached during the period.
unarrangedOverdraftObjectYesUnarranged overdraft sub-periods within this period.

unarrangedOverdraft

FieldTypeOptionalDescription
daysIntegerNoTotal unarranged overdraft days in the parent period.
periodsArray<Object>NoContiguous unarranged overdraft sub-periods.

Each periods[] element has start, end, days, and minimumBalance fields (plain-number balances).

Example (result message body)

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "fullAffordabilityReport": {
    "income": {
      "median": 2403.74,
      "medianIncludingTransfers": 2403.74,
      "amountConsistency": 0.99,
      "categoriesUsed": [
        {
          "uid": "27",
          "key": "deposits"
        }
      ],
      "longevity": {
        "consecutiveIncome": {
          "months": 12
        },
        "incomePeriodLength": {
          "months": 12
        }
      },
      "primaryIncomeAccount": {
        "uid": "b874c5fe-3dc1-4752-a93f-26b99320430c"
      },
      "regularIncome": {
        "isDetected": true,
        "predicted": {
          "monthly": {
            "amount": 2403.74
          }
        }
      }
    },
    "expenditure": {
      "cashWithdrawals": {
        "median": -161.32
      },
      "discretionary": {
        "median": -516.77
      },
      "fixed": {
        "median": -1455.11
      },
      "flexible": {
        "median": -808.26
      },
      "nonDiscretionary": {
        "median": -1748.96
      }
    },
    "transfers": {
      "median": -51.22,
      "out": {
        "median": -203.25
      }
    },
    "gambling": {
      "out": {
        "median": -100.26
      }
    },
    "loans": {
      "opened": {
        "details": []
      },
      "repayments": {
        "median": -283.35
      }
    },
    "returnedPayments": {
      "count": 0,
      "period": {
        "months": 11
      },
      "details": []
    },
    "overdrafts": {
      "usage": {
        "details": []
      }
    }
  }
}

Did this page help you?