Skip to content
Last updated

Field Specifications (FDIC Examination Ready)

Header Record Field Specifications

The Header Record contains reporter identification and file metadata. One Header Record per file.

Record Identifier

FieldLengthTypeValue
Record Identifier6AlphaHEADER

Program Identifiers

FieldLengthSourceDescription
Innovis Program Identifier10loan_type.metro2_innovis_program_identifierSubscriber code for Innovis
Equifax Program Identifier10loan_type.metro2_equifax_program_identifierSubscriber code for Equifax
Experian Program Identifier5loan_type.metro2_experian_program_identifierSubscriber code for Experian
TransUnion Program Identifier10loan_type.metro2_transunion_program_identifierSubscriber code for TransUnion

Logic: Only the program identifier for the target bureau is populated; others are blank.

Activity Date

FieldLengthTypeSource
Activity Date8Date (MMDDYYYY)month_end_date

Calculation:

activity_date = report_date.replace(day=1) - 1 day
# Example: report_date = 2026-01-15 → activity_date = 2025-12-31

Date Created

FieldLengthTypeSource
Date Created8Date (MMDDYYYY)utc_now().date()

Description: The date the file was generated.

Reporter Information

FieldLengthTypeSource
Reporter Name40Alphanumericloan_type.metro2_reporter_name
Reporter Address96Alphanumericloan_type.metro2_reporter_address
Reporter Telephone10Numericloan_type.metro2_reporter_telephone_number

Reporter Telephone Formatting:

  • Must be US phone number
  • Stored without country code
  • Format: 5551234567 (10 digits)

Software Information

FieldLengthTypeSource
Software Vendor Name40Alphanumericloan_type.metro2_software_vendor_name
Software Version5Alphanumericloan_type.metro2_software_version_number
MicroBilt/PRBC Identifier10Alphanumericloan_type.metro2_micro_bilt_prbc_program_identifier

Base Segment Field Specifications

The Base Segment contains the core account information. One per tradeline.

Record Descriptor Word

FieldLengthTypeDescription
Record Descriptor Word4NumericTotal record length in bytes (including this field)

Calculation:

rdw = len(record_string.encode()) + 4
# Formatted as 4-digit zero-padded number

Processing Indicator

FieldLengthTypeValue
Processing Indicator1Numeric1 (standard processing)

Time Stamp

FieldLengthTypeSource
Time Stamp14DateTimeutc_now().isoformat()

Format: MMDDYYYYHHMMSS

Identification Number

Field #LengthTypeSource
Field 320AlphanumericBureau-specific identifier from loan type

Logic:

field_name = {
  'Innovis': 'metro2_innovis_identification_number',
  'Equifax': 'metro2_equifax_identification_number',
  'Experian': 'metro2_experian_identification_number',
  'TransUnion': 'metro2_transunion_identification_number'
}[reporting_agency]

identification_number = loan_type[field_name]

# For migrated loans with account number change:
IF account_info_change_indicator.is_change_identification_number:
  identification_number = old_identification_number  # Report old in base
  # New number goes in L1 segment

Consumer Account Number

Field #LengthTypeSource
Field 530Alphanumericloan.external_id or loan.public_id

Logic:

IF credit_agency.use_loan_external_id AND loan.external_id:
  consumer_account_number = loan.external_id
ELSE:
  consumer_account_number = loan.public_id

# For migrated loans with account number change:
IF account_info_change_indicator.is_change_consumer_account_number:
  consumer_account_number = old_consumer_account_number  # Report old in base
  # New number goes in L1 segment

Portfolio Type

Field #LengthTypeSource
Field 61Alphaloan_type.metro2_portfolio_type

Values:

CodeDescription
CLine of Credit
IInstallment
MMortgage
OOpen
RRevolving

Account Type

Field #LengthTypeSource
Field 72Alphanumericloan_type.metro2_account_type

Formatting: Zero-padded (e.g., 01, 48)

Date Opened

Field #LengthTypeSource
Field 88Dateloan.activated_at

Format: MMDDYYYY

Credit Limit

Field #LengthTypeSource
Field 99MonetaryCalculated

Logic:

IF portfolio_type IN ('I', 'M'):  # Installment/Mortgage
  credit_limit = 0
ELSE:  # Open-ended
  credit_limit = loan.get_credit_limit(effective_at=snapshot_date)

RETURN round_based_on_loan_type(credit_limit)

Highest Credit Amount / Original Loan Amount

Field #LengthTypeSource
Field 109MonetaryCalculated

Logic:

IF portfolio_type IN ('I', 'M'):  # Installment/Mortgage
  highest_credit = loan.get_amount_financed_at_origination()
ELSE:  # Open-ended
  # Maximum principal balance during the reporting period
  highest_credit = max(snapshot.outstanding_balance_principal_amount for snapshot in period_snapshots)

RETURN round_based_on_loan_type(highest_credit)

Terms Duration

Field #LengthTypeSource
Field 113AlphanumericCalculated

Logic:

IF portfolio_type IN ('I', 'M'):  # Installment/Mortgage
  # Convert to months
  periods_per_month = AUTOPAY_TO_DUE_DATES[Monthly][loan.payment_frequency_at_origination]
  terms_duration = loan.duration_at_origination / periods_per_month
  RETURN format_as_integer(terms_duration)  # e.g., "036" for 36 months
ELSE:
  RETURN {
    'R': 'REV',  # Revolving
    'C': 'LOC',  # Line of Credit
    'O': '001'   # Open
  }[portfolio_type]

Terms Frequency

Field #LengthTypeSource
Field 121Alphaloan.current_periodic_payment_loan_schedule().frequency

Mapping:

Peach FrequencyMetro 2 Code
MonthlyM
TwiceMonthlyE
EveryTwoWeeksB
WeeklyW

Scheduled Monthly Payment Amount

Field #LengthTypeSource
Field 139MonetaryCalculated

Logic: See Calculations section.

Actual Payment Amount

Field #LengthTypeSource
Field 179MonetaryCalculated

Logic: See Calculations section.

Account Status

Field #LengthTypeSource
Field 17A2AlphanumericCalculated

Logic: See Account Status Codes section.

Payment Rating

Field #LengthTypeSource
Field 17B1AlphaCalculated

Logic: See Payment Rating and History section.

Payment History Profile

Field #LengthTypeSource
Field 1824AlphanumericCalculated

Logic: See Payment Rating and History section.

Special Comment

Field #LengthTypeSource
Field 192AlphanumericCalculated

Logic: See Special Circumstances section.

Compliance Condition Code

Field #LengthTypeSource
Field 202AlphanumericCalculated

Logic: See Special Circumstances section.

Current Balance

Field #LengthTypeSource
Field 219Monetarysnapshot.outstanding_balance_total_amount

Logic: See Calculations section.

Amount Past Due

Field #LengthTypeSource
Field 229MonetaryCalculated

Logic: See Calculations section.

Original Charge-off Amount

Field #LengthTypeSource
Field 239MonetaryLoanChargeOffProcessedEvent.amount

Logic:

IF snapshot.loan_status != 'ChargedOff' AND lender_status != '97':
  original_charge_off_amount = NULL  # Field left blank
ELSE:
  event = find_most_recent_charge_off_event(loan_id)
  IF event AND event.amount > 0:
    original_charge_off_amount = event.amount
  ELSE:
    # Fallback to current charged-off balance
    original_charge_off_amount = loan.balances.chargedOffBalances.chargedOffTotalAmount

Date of Account Information

Field #LengthTypeSource
Field 248DateCalculated

Logic:

IF loan.status IN ('Active', 'Accelerated', 'Frozen', 'ChargedOff'):
  date_of_account_info = month_end_date
ELIF loan.status = 'PaidOff':
  date_of_account_info = min(loan.paid_off_at.date(), month_end_date)
ELIF loan.status = 'Canceled':
  date_of_account_info = min(loan.canceled_at.date(), month_end_date)

FCRA Date of First Delinquency

Field #LengthTypeSource
Field 258DateCalculated

Logic:

FUNCTION calculate_fcra_dofd(loan, snapshot, account_status, payment_rating, 
                              consumer_info_indicator, reported_month):
  
  # For voluntary surrender
  IF lender_supplied_status = '95':
    IF loan.canceled_at:
      RETURN loan.canceled_at.date()
    RETURN reporting_status.reporting_end_date
  
  # For delinquent accounts
  IF account_status.is_non_current:
    due_date = get_latest_overdue_due_date()
    IF due_date:
      RETURN due_date + 30 days
  
  # For paid-off accounts that were delinquent
  IF account_status = '13' AND payment_rating.is_non_current:
    due_date = get_latest_overdue_due_date()
    IF due_date:
      RETURN due_date + 30 days
  
  # For bankruptcy with current status
  # CRITICAL: Only set DOFD from bankruptcy when specific conditions are met
  IF consumer_info_indicator IN ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', '1A', 'V'):
    IF account_status = '11' OR (account_status = '13' AND payment_rating = '0'):
      # Find qualifying bankruptcy case
      # CRITICAL: Loan must be associated with the case
      bk_case = find_case(
        type = 'bankruptcy',
        loan_associated = True,  # Loan must be linked to this case
        status IN ('Processing', 'Completed'),
        date_filter: (
          (reported_month >= case.courtCaseFiledDate::month/year 
           AND reported_month <= coalesce(case.courtCaseClosedDate::month/year,
                                           case.courtCaseDebtorDispositionDate::month/year))
          OR
          (reported_month >= case.courtCaseFiledDate::month/year 
           AND case.courtCaseClosedDate == empty 
           AND case.courtCaseDebtorDispositionDate == empty)
        )
      )
      
      # If multiple cases exist, select the most recent based on case.createdAt
      
      IF bk_case IS NOT NULL AND bk_case.courtCaseFiledDate IS NOT empty:
        RETURN bk_case.courtCaseFiledDate
  
  RETURN NULL  # No DOFD applicable

Date Closed

Field #LengthTypeSource
Field 268DateCalculated

Logic:

IF snapshot.loan_status = 'PaidOff' OR lender_status IN ('61', '63'):
  RETURN loan_paid_off_event.effective_at.date()

IF snapshot.loan_status = 'ChargedOff':
  IF has_outstanding_balance:
    IF is_installment:
      RETURN NULL
    ELIF loan.is_closed:  # LOC closed
      RETURN loan_closed_event.effective_at.date()
    ELSE:  # LOC open
      RETURN NULL
  ELSE:  # No balance
    RETURN date_outstanding_balance_went_zero

IF is_open_ended AND loan.is_closed:
  RETURN loan_closed_event.effective_at.date()

RETURN NULL

Date of Last Payment

Field #LengthTypeSource
Field 278DateCalculated

Logic: See Calculations section.

Interest Type Indicator

Field #LengthTypeSource
Field 281Alphaloan_type.metro2_interest_type_indicator

Values:

CodeDescription
FFixed
VVariable
(blank)Not applicable

Consumer Information Field Specifications

Consumer demographic information is included in the Base Segment.

Surname

FieldLengthTypeSource
Surname25Alphamain_borrower.last_name

Business Borrowers: Left blank if borrower type is Business.

First Name

FieldLengthTypeSource
First Name20Alphamain_borrower.first_name

Middle Name

FieldLengthTypeSource
Middle Name20Alphamain_borrower.middle_name

Generation Code

FieldLengthTypeSource
Generation Code1Alphamain_borrower.prefix

Mapping:

PrefixCode
JRJ
SRS
II2
III3
IV4
V5
VI6
VII7
VIII8
IX9

Social Security Number

FieldLengthTypeSource
SSN9NumericPersonIdentity (SSN type, primary)

Security: SSNs are tokenized in storage; actual values retrieved from secure tokenizer at file generation time.

Date of Birth

FieldLengthTypeSource
Date of Birth8Datemain_borrower.date_of_birth

Format: MMDDYYYY

Telephone Number

FieldLengthTypeSource
Telephone10NumericConsumer's phone from Contact records

Selection Logic:

  1. Primary Personal phone (Self affiliation)
  2. Secondary Personal phone (Self affiliation)
  3. Primary Home phone (Self affiliation)
  4. Secondary Home phone (Self affiliation)

Must be US phone number; non-US numbers excluded.

ECOA Code

FieldLengthTypeSource
ECOA Code1AlphaCalculated

Values:

CodeDescription
1Individual
2Joint Contractual Liability
3Authorized User
5Co-maker or Guarantor
7Maker
TTerminated
XDeceased
WBusiness/Commercial
ZDelete Consumer

Logic:

# Override check
override = get_one_time_field_value(EcoaCode)
IF override:
  RETURN override

# Deceased case
IF deceased_case_exists(status='Completed', outcome='Approved'):
  RETURN 'X'

# Delete due to data corruption
IF is_deleted AND deleted_reason = 'LoanDataCorrupted':
  RETURN 'Z'

# Business borrower
IF main_borrower.borrower_type = 'Business':
  RETURN 'W'

# Default
RETURN '1'  # Individual

Consumer Information Indicator

FieldLengthTypeSource
Consumer Info Indicator2AlphaCalculated

Logic: See Special Circumstances section.

Address Fields

FieldLengthTypeSource
Country Code2AlphaISO to Metro 2 mapping
First Line of Address32Alphaaddress.address_line1
Second Line of Address32Alphaaddress.address_line2
City20Alphaaddress.city
State2Alphaaddress.state
Postal Code9Alphaaddress.zip_code
Address Indicator1AlphaC (Verified) or Y (Known)

Address Selection: Primary address with status Primary is used. Only reported if address has Primary status.

Address Indicator Values:

CodeDescription
CVerified
YKnown to be address of primary consumer

Address Indicator Determination:

FUNCTION determine_address_indicator(address):
  IF address.verified = True:
    RETURN 'C'  # Address has been verified (e.g., through postal validation)
  ELSE:
    RETURN 'Y'  # Known to be address of primary consumer but not verified

Country Code Mapping: Peach uses ISO 3166-1 alpha-2 codes internally, which are mapped to Metro 2 country codes. Example:

  • USUS
  • CACN (Canada)
  • GBUK

Supplemental Segment Specifications

K1 Segment (Original Creditor)

The K1 Segment reports the original creditor when different from the current reporter.

Inclusion Criteria:

  • Not in metro2_skip_segments for the loan type
  • loan.originating_creditor_name_at_origination is populated

Fields:

FieldLengthTypeSource
Segment Identifier2AlphaK1
Original Creditor Name30Alphaloan.originating_creditor_name_at_origination
Creditor Classification2Numericloan_type.metro2_creditor_classification

K2 Segment (Purchased From / Sold To)

The K2 Segment reports ownership changes or collection agency assignments.

Inclusion Criteria:

  • Not in metro2_skip_segments
  • One of the following occurred in the reporting month:
    • Loan ownership changed with reportK2Segment: true
    • Collection agency assignment with report_k2_segment: true
    • Migration with metro2_k2_purchased_from_name set

Fields:

FieldLengthTypeSource
Segment Identifier2AlphaK2
Purchased From/Sold To Indicator1Numeric1 (Purchased From) or 2 (Sold To)
Name30AlphaNew owner/collector legal name

Purchased From/Sold To Logic:

IF migration_purchased_from_name (first report of migrated loan):
  indicator = '1'  # Purchased From
  name = migration_purchased_from_name
ELSE:
  indicator = '2'  # Sold To
  name = new_investor_legal_name OR collection_agency_legal_name

L1 Segment (Account Number Change)

The L1 Segment reports account number changes, typically during migration.

Inclusion Criteria:

  • Not in metro2_skip_segments
  • account_info_change_indicator is not empty
  • First report of a migrated loan with account number change

Fields:

FieldLengthTypeSource
Segment Identifier2AlphaL1
Account Info Change Indicator1NumericSee below
New Consumer Account Number30Alphaloan.public_id or loan.external_id
New Identification Number20AlphaBureau-specific identifier

Account Info Change Indicator Values:

CodeDescription
1Consumer Account Number changed only
2Identification Number changed only
3Both Consumer Account Number and Identification Number changed

Trailer Record Specifications

The Trailer Record contains control totals for file validation.

Record Structure

FieldLengthTypeDescription
Record Identifier7AlphaTRAILER
Total Base Records9NumericCount of Base Segments
Reserved9NumericZeros
Status DF Count9NumericCount of status DF records
Reserved27NumericZeros
Status DA Count9NumericCount of status DA records
Status 05 Count9NumericCount of status 05 records
Status 11 Count9NumericCount of status 11 records
Status 13 Count9NumericCount of status 13 records
.........(One field per status code)
ECOA Z Count9NumericCount of ECOA code Z records
K1 Segment Count9NumericCount of K1 segments
K2 Segment Count9NumericCount of K2 segments
SSN Count9NumericCount of records with SSN
SSN Count (duplicate)9NumericSame as above
DOB Count9NumericCount of records with DOB
DOB Count (duplicate x3)27NumericSame as above (3 times)
Phone Count9NumericCount of records with phone