CharityStack
Menu
← Blog

A clean donation file can still create duplicate gifts

Import donations into a nonprofit CRM without duplicates by separating donor matching from gift identity, staging exceptions, and testing the rerun.

C

CharityStack

·5 min read

Editorial card about repeat-safe donation imports over an Aurelia painting of a columned passage leading toward blue sky.

If you are deciding how to import donations into a nonprofit CRM, start by deciding how the system will recognize both the donor and the gift. A donor match can connect a row to the right person; only a stable gift key can stop the same transaction from becoming a second donation.

Use the source system and its transaction ID as that key. Keep the original export unchanged, stage your transformations separately, and close the import only when every source row is accepted, rejected, or already present.

Separate the donor match from the gift match

An email address may help you find a contact. It does not identify a donation. One donor can make several gifts with the same email, and a recurring file can contain the same gift you imported last month.

Treat the import as two decisions:

  1. Which contact owns this row? Match the source's donor or account identifier first when one exists. Otherwise use your CRM's reviewed contact-matching rules.
  2. Has this gift already been created? Compare a stable gift key, such as `source name + source transaction ID`, with prior imports.

Current import tools expose this boundary in different ways. CharityEngine supports platform contact IDs and configured external contact IDs when associating imported transactions. Donorbox asks the importer to choose supporter match criteria and can update supporter fields during the same import. Those are contact controls. Your team still needs a transaction-level rule that prevents one source gift from landing twice.

If your destination cannot reject a gift key that already exists, do not rerun the full file. Filter it against your import log first or hold the import until you have a supported duplicate control.

Put every file inside an import envelope

Keep four pieces together for each source and reporting period:

  • the untouched source export;
  • a staged file containing your mapped columns;
  • an exception list for rows you did not import; and
  • a control record with row counts, amounts, operator, date, and final status.

This is the import envelope. It lets another person reconstruct what arrived, what changed, what entered the CRM, and what still needs work. It also keeps cleanup formulas and renamed columns out of the only copy of the source evidence.

Use a separate envelope for each payout report, workplace-giving file, or third-party portal. If one file mixes employee gifts, employer matches, grants, or other record types, classify those rows before mapping them. Do not force unlike records through one generic donation template.

The gift-intake packet answers who reviews money facts and donor context. The import envelope adds the file-level evidence needed when many gifts arrive together.

Reject ambiguity before it reaches the CRM

A clean-looking spreadsheet can still contain unsafe rows. Hold a row when any of these is true:

  • the source transaction ID is missing or repeated;
  • the amount, currency, or gift date is missing or invalid;
  • the fund or campaign value has no approved destination mapping;
  • the donor match points to more than one contact; or
  • the row would overwrite trusted contact information without review.

Do not solve an ambiguous donor by attaching the gift to the first similar name. Keep the transaction in the exception list with its source key, reason, and owner. If the question is whether two contacts are actually one person, use the donor duplicate checks before merging or reassigning anything.

The safe outcome is not “every row imported.” It is “every row has a known disposition.” A rejected row remains visible and can be corrected later without rerunning rows that already passed.

Test the rules on a small sample

Choose a sample that exercises the difficult cases, not merely the first five lines. Include an existing donor, a new donor, a repeated donor with a different gift, a known duplicate gift key, and one row that should fail.

CharityEngine's current guidance recommends a small sample import so the operator can verify the result before loading the full file. Your acceptance test should confirm more than a successful upload message:

  • accepted rows created the intended gifts on the intended contacts;
  • the repeated gift key did not create another gift;
  • the rejected row stayed out of the CRM with a recorded reason;
  • mapped funds, campaigns, dates, amounts, and payment methods remained correct; and
  • supporter fields changed only where your rule allowed them to change.

Delete-and-retry is not a safe test plan unless your product documents a complete rollback. If the sample fails, correct the staging rule and start with a new test file whose rows you can identify precisely.

Reconcile rows and amounts, then test the rerun

Close the import with a simple equation:

`source rows = accepted + rejected + already present`

Run the same check for the source amount. A matching dollar total alone is not enough: one missing $50 gift and one duplicate $50 gift can cancel each other out. The row disposition proves completeness; the amount check catches a different class of error.

Then rerun the exact staged sample. A safe process should create no additional gifts. It may report that every key already exists, or your import log may remove those rows before they reach the destination. Either result is acceptable if it is documented and repeatable.

Beacon's current Stewardship import guide uses source and external IDs for imported objects and makes its deduplication choices explicit. Your CRM's fields will differ, but the operating test is the same: the second pass must not change the gift count.

Make the next file boring

Save the approved mappings, source-key rule, exception reasons, test evidence, and completed control record. When the next report arrives, create a new envelope and run the same checks. Do not copy last month's final file and paste new rows into it; that blurs the boundary between source periods and makes a partial rerun harder to prove.

If a new source cannot provide a stable transaction identifier, pause before importing. Ask the source for a durable ID or create a documented source-side key from fields that cannot collide within that source. If neither is possible, manual entry with explicit duplicate review may be safer than a bulk import.

Keep fundraising operations connected

Keep donor records, gifts, and fundraising operations connected in one system.

Start fundraising free →