Migrating nonprofit data from Staruslive → Blackbaud RE NXT using Power Automate

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_nameconstituent.first

contact.last_nameconstituent.last

contact.emailconstituent.email.address

donation.amountgift.amount.value

donation.dategift.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.

Tagged:

Answers

  • Alex Wong
    Alex Wong Community All-Star
    Tenth Anniversary Facilitator 5 Kudos 5 bbcon 2025 Attendee Badge

    That's a great post of your effort in this migration. A few tips (maybe):

    • PA flow run history is only 28 days. a good log, but don't use it as a "full audit trail".
    • Daily API limit does not apply to PA Blackbaud connector, unless you are using HTTP action to make the SKY API calls.
    • There is still a 10 api call per seconds limit that will trigger 429 rate limit exceeded error, so as long as you are not working concurrently, this limit should not be reached.
    • Though, concurrency will increase speed, making your flow run faster, I wouldn't go beyond 3 concurrent process, as each "constituent" will have additional calls (gift, email, address, etc) within the loop. But increasing 3x the speed is still worth it.

Categories