Skip to main content

Where the data lives

Credit report data lives in book_meta from GET /books/:id. Read it at book["book_meta"]["parser_v2_credit_report"].
r = requests.get(f"{API_BASE}/books/{book_id}", headers=headers)
book = r.json()
cr = book["book_meta"]["parser_v2_credit_report"]
parser_v2_credit_report is null if the book has no parsed credit report.

Subject entity

entity = cr["primary_entity"]
print(f"Name:  {entity['full_name']}")
print(f"DOB:   {entity.get('date_of_birth', 'N/A')}")

for addr in entity.get("address", []):
    if addr.get("is_primary"):
        print(f"Address: {addr['address_line_1']}, {addr['city']}, {addr['state']} {addr['zip_code']}")

FICO scores by bureau

The report can contain data from up to three bureaus: Experian, Equifax, TransUnion.
for bureau_data in cr["credit_report_body"]:
    bureau = bureau_data["credit_bureau"]["display_name"]
    fico = bureau_data.get("fico_score") or {}
    score = fico.get("score")
    date = fico.get("date_of_score")
    print(f"{bureau}: FICO {score} (as of {date})")

Accounts by bureau

Each bureau has an underwritten_accounts[] list.
for bureau_data in cr["credit_report_body"]:
    bureau = bureau_data["credit_bureau"]["display_name"]
    accounts = bureau_data["underwritten_accounts"]

    print(f"\n{bureau} ({len(accounts)} accounts)")

    for acct in accounts:
        status = acct.get("account_status_normalized", "unknown")
        acct_type = acct.get("account_type_normalized", "")
        balance = acct.get("recent_balance")
        limit = acct.get("credit_limit")

        print(f"  {acct['account_name']} ({acct_type}) {status}")
        if balance is not None:
            print(f"    Balance: ${balance:,.2f}"
                  + (f" / ${limit:,.2f} limit" if limit else ""))
        if acct.get("monthly_payment"):
            print(f"    Monthly payment: ${acct['monthly_payment']:,.2f}")
Account status values: current, delinquent, charged_off, collection, bankruptcy, foreclosure, repossession, settled, closed, unknown Account type values: revolving, installment, mortgage, charge, other

Derogatory accounts

derogatory_statuses = {"delinquent", "charged_off", "collection", "bankruptcy",
                        "foreclosure", "repossession", "settled"}

for bureau_data in cr["credit_report_body"]:
    bureau = bureau_data["credit_bureau"]["display_name"]
    derogatories = [
        a for a in bureau_data["underwritten_accounts"]
        if a.get("account_status_normalized") in derogatory_statuses
    ]
    if derogatories:
        print(f"\n{bureau} derogatory accounts:")
        for acct in derogatories:
            print(f"  {acct['account_name']}: {acct['account_status_normalized']}")

Hard inquiries

for bureau_data in cr["credit_report_body"]:
    bureau = bureau_data["credit_bureau"]["display_name"]
    inquiries = bureau_data["credit_bureau"].get("inquiries") or []
    print(f"\n{bureau} inquiries ({len(inquiries)}):")
    for inq in inquiries:
        print(f"  {inq['inquiry_date']}  {inq.get('creditor_name', 'Unknown')}")

Total monthly debt obligations

Use a dedup set to avoid counting the same account twice across bureaus.
total_monthly = 0
seen = set()

for bureau_data in cr["credit_report_body"]:
    for acct in bureau_data["underwritten_accounts"]:
        key = (acct.get("account_name", ""), acct.get("account_number", ""))
        if key not in seen and acct.get("is_open") and acct.get("monthly_payment"):
            seen.add(key)
            total_monthly += acct["monthly_payment"]

print(f"Total monthly obligations: ${total_monthly:,.2f}")

Self-reported and authorized user accounts

Pathway flags these so you can exclude them from underwriting.
for bureau_data in cr["credit_report_body"]:
    for acct in bureau_data["underwritten_accounts"]:
        if acct.get("is_authorized_user"):
            print(f"AU account: {acct['account_name']}")
        if acct.get("is_self_reported"):
            print(f"Self-reported: {acct['account_name']}")

Full credit summary

def credit_summary(cr):
    all_accounts = [
        acct
        for bureau_data in cr["credit_report_body"]
        for acct in bureau_data["underwritten_accounts"]
        if not acct.get("is_authorized_user")
        and not acct.get("is_self_reported")
    ]

    derogatory = {"delinquent", "charged_off", "collection", "bankruptcy",
                  "foreclosure", "repossession", "settled"}

    fico_scores = [
        bureau_data["fico_score"]["score"]
        for bureau_data in cr["credit_report_body"]
        if bureau_data.get("fico_score") and bureau_data["fico_score"].get("score")
    ]

    return {
        "entity": cr["primary_entity"]["full_name"],
        "fico_scores": fico_scores,
        "median_fico": sorted(fico_scores)[len(fico_scores) // 2] if fico_scores else None,
        "open_accounts": sum(1 for a in all_accounts if a.get("is_open")),
        "derogatory_accounts": sum(1 for a in all_accounts if a.get("account_status_normalized") in derogatory),
        "total_revolving_balance": sum(
            (a.get("recent_balance") or 0)
            for a in all_accounts
            if a.get("account_type_normalized") == "revolving" and a.get("is_open")
        ),
        "total_monthly_obligations": sum(
            (a.get("monthly_payment") or 0)
            for a in all_accounts
            if a.get("is_open")
        ),
    }