Wanted to share our recent data migration experience moving a nonprofit organization's full constituent and fundraising history from Staruslive to Blackbaud RE NXT — fully orchestrated through Microsoft Power Automate, with zero manual import/export steps.
Why we chose Power Automate over a one-shot CSV import:
The organization needed a live, auditable, re-runnable pipeline — not a one-time bulk upload. Power Automate gave us incremental retry logic, per-record error trapping, and a full run history that served as the migration audit log.
The migration architecture step by step:
Step 1 — Extract from Staruslive (scheduled HTTP trigger) Staruslive exposes a REST API. We used Power Automate's HTTP action with Bearer auth to call:
GET /api/v1/contacts?page=1&per_page=100
A Do Until loop paginated through all records, storing batches in a SharePoint list as a staging buffer. For organizations without API access, we used Staruslive's CSV export, read into Power Automate via Excel Online (Business) → List rows present in a table.
Step 2 — Transform & map fields (Compose + Select actions)
Key field mappings handled via Compose actions:
• contact.first_name → constituent.first
• contact.last_name → constituent.last
• contact.email → constituent.email.address
• donation.amount → gift.amount.value
• donation.date → gift.date (ISO 8601 formatted via formatDateTime())
• membership.plan_name → custom RE NXT constituent attribute
Note: Staruslive stores phone numbers without formatting — we normalized using a Power Automate expression: replace(replace(item()?['phone'],'-',''),'(','')) before POSTing.
Step 3 — Duplicate check via RE NXT search API
Before creating any record, we called:
GET /constituent/v1/constituents/search?email={email}
If a match is returned → PATCH the existing constituent.
If no match → POST new constituent.
This prevents duplicate constituents even on re-runs.
Step 4 — POST constituents to RE NXT SKY APIPOST https://api.sky.blackbaud.com/constituent/v1/constituents
Headers: Bb-Api-Subscription-Key + OAuth 2.0 Bearer token (auto-refreshed via a child flow running every 55 minutes using a Recurrence trigger + HTTP action to the SKY token endpoint).
Step 5 — POST linked records (gifts, addresses, phones) Using the returned constituent id, we chained:
• POST /gift/v1/gifts — migrates each donation with fund code, amount, date, and payment type
• POST /constituent/v1/addresses — mailing and billing addresses
• POST /constituent/v1/phones — primary and mobile numbers
Each is wrapped in a Scope with Configure run after: has failed to log failures to a SharePoint error table without stopping the full run.
Step 6 — Membership & event participant migration
• Membership records mapped to RE NXT Constituent Attributes (custom fields) since RE NXT manages memberships at the organization level.
• Event participants posted to POST /event/v1/eventparticipants after confirming the target event exists via GET /event/v1/events?search=....
Step 7 — Error logging & reconciliation report
Failed records are written to a SharePoint list with columns: source_id, error_code, error_message, timestamp. After each run, Power Automate sends a summary email: total processed, successful, failed, and a link to the error log — making reconciliation fast and auditable.
Migration results for our client:
🏆 ~4,200 constituent records migrated with 99.1% success rate on first run
🏆 ~12,000 historical gift records transferred with fund and date integrity
🏆 Duplicate-safe — 0 duplicate constituents created
🏆 Full audit trail — every record traceable through Power Automate run history
🏆 Re-runnable — reruns only process failed/missing records (idempotent by design)
🏆 No manual CSV manipulation — fully automated, end to end
Gotchas we hit (so you don't have to):⚠️ RE NXT throttles at 10,000 API calls/day on standard tier — we added a Delay action (0.5s) between each constituent POST to stay safely under limit.
⚠️ formatDateTime() in Power Automate outputs UTC RE NXT expects ISO 8601 with timezone offset. Use: convertTimeZone(item()?['donation_date'],'UTC','Central Standard Time').
⚠️ Staruslive membership plan names don't map 1:1 to RE NXT membership categories we created a lookup table in SharePoint and used a Get items (filtered) action to resolve each plan before POSTing.