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
| Scenario | Approach |
|---|---|
| Submitting a donation where Raise should match or create the donor automatically | Skip this workflow — let POST /api/Raise/give handle donor matching via the embedded donor block. |
| Syncing donors from another system (HR, ESP, etc.) into Raise without an associated donation | Search first, then submit a donation in test mode (and refund) to provoke donor creation — or coordinate through the admin team. |
| Building an integration that needs to verify a donor exists before another operation | Use the search/lookup pattern below. |
| Updating an existing donor’s information | Find the donor first, then call PUT or PATCH against /api/Donor/{id}. |
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
Use /api/Donor/search when | Use POST /api/Donor/query when |
|---|---|
| You have a single identifier (email, phone, ID) and want a quick lookup | You need structured filtering (multiple fields with AND/OR logic) |
| Type-ahead suggestions in a UI | Batch reconciliation across thousands of donors |
| Investigating “is this donor in the system?” | Building segments or exports |
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:| Defense | Description |
|---|---|
Use POST /api/Raise/give for matching | The donation endpoint handles matching atomically — concurrent submissions for the same donor email don’t create duplicates. |
| Serialize by email at the integration level | If your integration manages donor creation outside of /api/Raise/give, use a per-email lock or queue to serialize concurrent creates. |
| Detect and merge | If duplicates do occur, use PUT /api/Donor/merge to consolidate them — see Donors: Merge. |
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+.