Skip to content

Get your CRM export in

One call, read_gifts(path_or_rows, source=...), turns a gift export from any of the five CRMs below into the donor-level feature table every model in this library expects. Pick your CRM's tab for the exact column mapping and a runnable example; export steps vary by CRM configuration and version, so treat them as a starting point, not exact click-by-click instructions.

Run a gift export or query (Raiser's Edge NXT: Reports > Gift reports, or Query for a custom pull) and include at minimum the constituent ID, gift date, gift amount, and gift type columns, saved as CSV.

Your column Maps to Notes
Constituent ID (or constit_id, donor_id) contact_id required
Gift Date (or Pledged on for a pledge row) receive_date required
Gift Amount total_amount required
Gift Type excluded via exclude_gift_types pledges are excluded by default so a promise isn't double-counted with its payments
from philanthropy.ingest import read_gifts

rows = [
    {"Constituent ID": "88", "Gift Date": "2025-01-10",
     "Gift Amount": "1200.00", "Gift Type": "Pledge"},
    {"Constituent ID": "88", "Gift Date": "2025-02-10",
     "Gift Amount": "100.00", "Gift Type": "Pay-Cash"},
]
features = read_gifts(rows, source="raisers_edge")
print(features.loc["88", "total_gift_amount"])  # 100.0: the pledge is excluded

A real export is a CSV file with these same column headers; pass its path instead of a list of rows: read_gifts("gifts.csv", source="raisers_edge").

Export your Opportunity report (Reports > New Report, an Opportunity report type) with the account/contact key, close date, amount, and stage columns, saved as CSV.

Your column Maps to Notes
Account ID (or AccountId, Primary Contact) contact_id required
Close Date receive_date required
Amount total_amount required
Stage filtered via include_stages only Closed Won counts as money received by default; Pledged is excluded
from philanthropy.ingest import read_gifts

rows = [
    {"Account ID": "88", "Close Date": "2025-01-10",
     "Amount": "100.00", "Stage": "Pledged"},
    {"Account ID": "88", "Close Date": "2025-02-10",
     "Amount": "100.00", "Stage": "Closed Won"},
]
features = read_gifts(rows, source="npsp")
print(features.loc["88", "total_gift_amount"])  # 100.0: the pledge is excluded

A real export is a CSV file with these same column headers; pass its path instead of a list of rows: read_gifts("gifts.csv", source="npsp").

Export your transaction list (Transactions > Export) with the account number, date, amount, and transaction type columns, saved as CSV.

Your column Maps to Notes
Account Number (or AccountId) contact_id required
Date receive_date required
Amount total_amount required
Transaction Type filtered via exclude_entry_types Pledge rows are excluded by default so the promise isn't double-counted with its PledgePayment rows
from philanthropy.ingest import read_gifts

rows = [
    {"Account Number": "88", "Date": "2025-01-10",
     "Amount": "1200.00", "Transaction Type": "Pledge"},
    {"Account Number": "88", "Date": "2025-02-10",
     "Amount": "100.00", "Transaction Type": "PledgePayment"},
]
features = read_gifts(rows, source="bloomerang")
print(features.loc["88", "total_gift_amount"])  # 100.0: the pledge is excluded

A real export is a CSV file with these same column headers; pass its path instead of a list of rows: read_gifts("gifts.csv", source="bloomerang").

Export a gift report (Reports > Report Writer, or the "Gift/Pledge detail" canned report) with the donor ID, gift date, gift amount, and record type columns, saved as CSV.

Your column Maps to Notes
Donor ID (or DonorID) contact_id required
Gift Date receive_date required
Gift Amount total_amount required
Record Type filtered via exclude_record_types P (Pledge) and M (a split gift's Main total) are excluded by default; G (a regular gift or pledge payment) counts
from philanthropy.ingest import read_gifts

rows = [
    {"Donor ID": "88", "Gift Date": "2025-01-10",
     "Gift Amount": "1200.00", "Record Type": "P"},
    {"Donor ID": "88", "Gift Date": "2025-02-10",
     "Gift Amount": "100.00", "Record Type": "G"},
]
features = read_gifts(rows, source="donorperfect")
print(features.loc["88", "total_gift_amount"])  # 100.0: the pledge is excluded

A real export is a CSV file with these same column headers; pass its path instead of a list of rows: read_gifts("gifts.csv", source="donorperfect").

Export a contribution search result (Search > Find Contributions, or the equivalent APIv4 Contribution.get call) with the contact ID, contribution date, total amount, and contribution status columns, saved as CSV.

Your column Maps to Notes
Contact ID contact_id required
Contribution Date (or receive_date from an APIv4 pull) receive_date required
Total Amount total_amount required
Contribution Status filtered via statuses only Completed counts by default; Failed, Cancelled, and pending statuses are excluded
from philanthropy.ingest import read_gifts

rows = [
    {"Contact ID": "101", "Contribution Date": "2025-01-15",
     "Total Amount": "250.00", "Contribution Status": "Completed"},
    {"Contact ID": "101", "Contribution Date": "2025-06-02",
     "Total Amount": "99.00", "Contribution Status": "Failed"},
]
features = read_gifts(rows, source="civicrm")
print(features.loc["101", "total_gift_amount"])  # 250.0: the failed contribution is excluded

A real export is a CSV file with these same column headers; pass its path instead of a list of rows: read_gifts("gifts.csv", source="civicrm").

Next step

read_gifts returns one row per donor, indexed by contact_id, with columns like total_gift_amount, gift_count, and recency_days. Feed that straight into a model, e.g. DonorPropensityModel or LapsePredictor, the same way the Results pages do, or see Use the CLI to run this from the command line without writing any code.