POST /api/Donor for net-new donor creation. Donor records typically come into existence in one of two ways:
- Implicitly through
POST /api/Raise/givewhen a donation is submitted (most common). - Through
PUT /api/Donor/{id}with the full donor record — but this requires an existing donor ID, so it’s effectively an update or upsert at a known ID.
When to use this workflow
For routine donations, donor matching is handled automatically by the donation submission endpoint — see Process a Donation: Prepare the donor block. This workflow is for the cases where matching needs to happen explicitly.
Pattern 1: lookup by email via GET /api/Donor/search
The cheapest and most direct lookup. The search endpoint accepts a free-text filter string and matches against multiple fields — including ID, name, email, phone, postal code, and state:
cURL
Search for donors by a filter string. Can match on donor ID, first name, last name, organization name, phone number, email address, postal code, and state. Supports searching by first/last name combinations, name with state, name with postal code, phone number in (xxx) xxx-xxxx format, and email in angle brackets.
So the search endpoint will accept:
- A bare email:
bruce@wayne.example - An email in angle brackets:
<bruce@wayne.example> - A phone number in
(xxx) xxx-xxxxformat - A name with state qualifier:
Bruce Wayne, NJ - A name with postal code:
Bruce Wayne 10001 - A bare donor ID
JavaScript
When to prefer search over query
For most integration workflows that ask “does this email already exist as a donor?”,
search is the right answer.
Pattern 2: structured filter via POST /api/Donor/query
For more deterministic matching — exact email equality without partial matches on other fields — the query endpoint is more precise:
cURL
operator: 0 value here is a placeholder — the integer-to-label mapping for query operators must be discovered through GET /api/Query/options/{queryType} since the spec doesn’t expose it. See Pagination and Filtering: Discovering query options and the Spec gap warning on operator integer values.
JavaScript
search but produces exact matches without the fuzzy-matching behavior of the search endpoint. Use it when you need to be certain that the returned donor matches the input email exactly.
Pattern 3: lookup by stored ID via GET /api/Donor/{donorId}
If your integration already has a Raise donor ID stored from a previous operation — typically because a prior gift or interaction surfaced it — the cheapest lookup is by ID directly:
cURL
404 response means the donor was deleted (or the ID is wrong). A 200 returns the full record including all sub-resources when includeDetails semantics apply.
This is the cheapest lookup because it’s a single record fetch with no filter evaluation. Cache donor IDs from previous interactions and use them when possible.
When no match is found
Ifsearch or query returns no matching donor, three paths forward:
Path A: let POST /api/Raise/give create the donor (recommended for live donations)
If the workflow is heading toward a donation anyway, don’t pre-create the donor. Let the donation submission handle creation:
JavaScript
donorId of the matched-or-created donor.
This is the recommended path for any workflow that will produce a donation. It avoids race conditions where two workflows simultaneously try to create the same donor.
Path B: seed the donor through admin tools (for non-donation onboarding)
For integrations that need donors to exist in Raise without a corresponding donation — for example, a CRM-driven workflow that registers a prospective donor before they’ve given — the practical path is to coordinate with the customer’s admin team:- The customer’s Raise administrator can create the donor through the admin UI.
- The customer’s bulk import tools can ingest a list of donors from a CSV.
Future versions of the Raise API are expected to add direct donor-creation endpoints. Until then, partner integrations that need bulk donor seeding should coordinate with the customer’s admin team rather than building around the absence of the endpoint.⚠️ Spec gap: No top-level
POST /api/Donor endpoint exists for net-new donor creation. The CreateDonorRequest schema in the spec is referenced only by PUT /api/Donor/{id} (where the donor must already exist). Confirm with the platform team if a true create endpoint is on the v2 roadmap.Path C: provoke creation through a test-mode donation (development only)
For development environments where you need to script donor creation without an admin UI, you can submit a small test-mode donation throughPOST /api/Raise/give with isTestMode: true. The donor will be created (or matched) by the donation flow:
JavaScript
Updating a donor after finding them
Once you have a donor ID — from a search match or a freshly-created donor — the update operations are:Full or partial update of the donor record
cURL
PATCH /api/Donor/{id} updates only the fields included in the body. PUT /api/Donor/{id} replaces the full record. Prefer PATCH unless you have a specific reason to replace everything.
Adding sub-resources
For adding addresses, emails, or phone numbers without replacing the existing ones, use the sub-resource endpoints:cURL
A complete create-or-find function
Pulling the patterns together:JavaScript
A common pitfall: race conditions
Two workflows running in parallel both look up the same donor by email, both find no match, both create the donor. Without explicit locking or idempotency, this can produce duplicate donor records. The defenses:
The race-condition defense is one of the strongest arguments for letting
POST /api/Raise/give handle donor creation rather than pre-creating donors yourself.
Where to go next
Process a Donation
The donation submission workflow that creates donors implicitly through
POST /api/Raise/give.Query Donors by Filters
The structured-query pattern for bulk donor reads.
Donors
The Donor resource reference — fields, sub-resources, and special operations.
How Raise Data Flows to CRM+
How donors created in Raise become Contacts in CRM+.