DonorPerfect Online XML API
Reference for integrating with the DonorPerfect Online (DP) XML API (SofterWare, Inc.) — User Manual v7.1, corresponding to DonorPerfect Online 2024.02.16. The DP API is an HTTPS-only XML-returning API exposing both predefined stored-procedure-like calls and ad-hoc SQL SELECT queries against the underlying MS SQL Server 2019 database.
Base URL
https://www.donorperfect.net/prod/xmlrequest.asp
All requests are HTTPS GET. There is one endpoint — operations are dispatched via the action query parameter.
Authentication
Single API key per DP user account, provided by DonorPerfect Support / API Help Desk (api@softerware.com).
?apikey=<your-api-key>
| Rule | Detail |
|---|---|
| Quoting | API key must NOT be wrapped in quotes |
| URL encoding | API key must NOT be URL-encoded |
| Position | Can appear before OR after action+params |
| User binding | Tied to a DP user account, but DP user permissions DO NOT restrict API calls — the key has full data access |
| Password rotation | DP user password expiry does NOT affect the API key |
Audit trail: Most write calls accept an
@user_idparameter (≤20 chars) for audit logging. This is a free-form string — not validated against actual DP users. Use your application name (e.g.,'MyAppName') so changes can be attributed.
Request Anatomy
https://www.donorperfect.net/prod/xmlrequest.asp?apikey=xxxxx&action=dp_gifts¶ms=@donor_id=640
| Segment | Purpose |
|---|---|
| Preamble | https://www.donorperfect.net/prod/xmlrequest.asp — fixed |
apikey=... |
Credentials (no quotes, not URL-encoded) |
action=... |
Either a predefined procedure name (dp_savegift, etc.) OR a raw SQL statement (SELECT ...) |
params=... |
Comma-separated parameter list for predefined procedures; URL-encoded |
Parameter Formats
Named parameters (recommended — order-independent, easier to debug):
¶ms=@donor_id=0, @first_name='Orianthi', @last_name='Panagaris', @user_id='MyAppName'
Positional parameters (legacy, still supported):
¶ms=0,'Orianthi','Panagaris',null,null,...
| Rule | Detail |
|---|---|
| Date format | 'MM/DD/YYYY' only — time values are NOT supported |
| Strings | Single-quoted |
| Escapes | Embed apostrophe as two single quotes: 'O''Reilly' |
| Unicode | Prefix string with N: @field=N'Phúc cho những' (system must be Unicode-enabled by DP Support) |
| Empty/missing | Use null, NOT ''. Searching '' returns nothing |
| Mixing | Cannot mix named and positional parameters in a single call |
| URL encoding | Everything after action= should be URL-encoded; the apikey must NOT be |
| Whitespace | Do NOT put spaces in the leading portion of the URL — causes "@donor_id not supplied" errors |
Response Format
All responses are XML. Each row is a <record> containing one <field> per column:
<result>
<record>
<field name="donor_id" id="donor_id" value="147"/>
<field name="first_name" id="first_name" value="Orianthi"/>
<field name="last_name" id="last_name" value="Panagaris"/>
...
</record>
</result>
For create/update calls, the result is a single <field> with the new/affected ID:
<result>
<record>
<field name="" id="" value="10230" />
</record>
</result>
Limits & Admin
| Limit | Value |
|---|---|
| Row retrieval limit | 500 rows per query — paginate with TOP 500 ... WHERE id > {last_id} ORDER BY id |
| Concurrent user blocking | None for API |
| SmartActions | NOT triggered by API writes |
| Logging | All API requests are logged by DP for troubleshooting and fraud detection |
| Service guarantee | Best effort — no SLA |
| API change policy | SofterWare reserves the right to change the interface; tracked in DP Community Release Notes |
Two Execution Modes
The DP API has two distinct ways to call it. Prefer Predefined Procedures whenever one fits.
1. Predefined Procedures
Stored-procedure-style calls. Invoked as action=dp_<name> with ¶ms= containing named parameters.
2. Dynamic Queries (SQL SELECT)
Raw ANSI SQL passed as the action value — runs against the underlying MS SQL Server 2019 database.
&action=SELECT donor_id, first_name, last_name FROM dp WHERE last_name = 'bacon'
Supports JOIN, wildcards (%), TOP N, ORDER BY, COALESCE, etc. Only the SQL features documented in this skill are guaranteed to work — DP supports a limited SQL subset.
Avoid SELECT * in production code — slow and brittle to schema changes. Use it only for ad-hoc exploration of a single record.
Predefined Procedures
Donor / Constituent
| Procedure | Purpose |
|---|---|
dp_donorsearch |
Search donors by demographic fields (% wildcard, NULL = match anything) |
dp_savedonor |
Create (@donor_id=0) or update donor; updates OVERWRITE existing values |
dp_saveaddress |
Create/update secondary "seasonal" address on DPADDRESS |
dp_saveotherinfo |
Create/update Other Info entry on DPTHERINFO (returns other_id for UDF saves) |
dp_savecontact |
Create/update Contact (activity/task) on DPCONTACT |
dp_savelink |
Create relationship link between two donors (reciprocal auto-created) |
Gifts, Pledges, EFT
| Procedure | Purpose |
|---|---|
dp_gifts |
List a predefined set of fields for all gifts of a donor |
dp_savegift |
Create/update gift, pledge payment, soft credit, split gift entry, or gift adjustment |
dp_savepledge |
Create/update a parent pledge (recurring gift schedule) |
dp_PaymentMethod_Insert |
Insert EFT payment method (DPPAYMENTMETHOD) — requires SafeSave Customer Vault ID |
dp_PaymentMethod_Update |
Update EFT payment method — MUST re-supply all existing values |
Tributes (In Honor Of / In Memory Of)
| Procedure | Purpose |
|---|---|
dp_tribAnon_MyTribSummary |
List all tributes (or active only) |
dp_tribAnon_Search |
Search tributes by name keyword |
dp_tribAnon_Create |
Create a new tribute |
dp_tribAnon_AssocTribsToGift |
Associate one or more tributes with a gift |
dp_tribAnon_SaveTribRecipient |
Add a notification recipient for one specific gift |
dp_tribNotif_Save |
Create the actual notification gift record (follow-up to SaveTribRecipient) |
dp_tribAnon_Update |
Update tribute properties AND recipient list (full set replace — include existing!) |
Custom Fields, Codes, Checkboxes, Flags
| Procedure | Purpose |
|---|---|
dp_save_udf_xml |
Save a single UDF value — @matching_id selects table (donor_id→DPUDF, gift_id→DPGIFTUDF, contact_id→DPCONTACTUDF, other_id→DPTHERINFOUDF, address_id→DPADDRESSUDF) |
dp_savecode |
Add/update DPCODES drop-down values (GL codes, solicit codes, campaigns, etc.) |
mergemultivalues |
Preferred — set the full set of checked codes for a checkbox field; unspecified codes get unchecked |
dp_savemultivalue_xml |
Set a single checkbox value (legacy — prefer mergemultivalues) |
dp_deletemultivalues_xml |
Delete ALL checked checkboxes on a screen tab for a donor |
dp_saveflag_xml |
Set a single flag on a donor (DPFLAGS — Main tab) |
dp_delflags_xml |
Delete ALL flags for a donor (individual flag delete is not supported) |
Full parameter tables for every procedure are in
references/procedures.json.
Database Tables (Dynamic Queries)
Sources of truth for SELECT-style retrieval and for understanding the data model behind the procedures.
| Table | Purpose |
|---|---|
DP |
Primary donor / constituent record |
DPUDF |
User-defined fields on donors |
DPCODES |
Drop-down code values for all coded fields |
DPUSERMULTIVALUES |
Checkbox values (one row per checked code per donor) |
DPFLAGS |
Donor flags (top of Main tab) |
DPGIFT |
Gift / pledge / transaction records |
DPGIFTUDF |
UDFs on gifts (incl. EFT field that enables auto-charge) |
DPADDRESS |
Secondary / seasonal addresses (Address tab) |
DPADDRESSUDF |
UDFs on addresses |
DPLINK |
Donor-to-donor relationships (Links tab) |
DPCONTACT |
Contact / activity / task records (Contacts tab) |
DPCONTACTUDF |
UDFs on contacts |
DPTHERINFO |
"Other Info" tab records |
DPTHERINFOUDF |
UDFs on Other Info (Quebec Law 25 PO_* fields live here) |
DPTRIBUTESANON |
Tributes — name, type, active flag, notification person |
DPTRIBUTESANON_GIFTASSOC |
Gift ↔ tribute many-to-many association |
DPTRIBUTESANON_RECIPIENTS |
Tribute recipient list |
DPPAYMENTMETHOD |
EFT payment methods (Accounts tab) |
SD_FIELD |
Field metadata — query before UDF writes to check field exists |
Full column lists and notes are in
references/tables.json.
Key Entities & Relationships
| Entity | Description |
|---|---|
| Donor / Constituent | Individual or organization (ORG_REC='Y') record on DP |
| Gift | A donation, pledge, pledge payment, soft credit, or adjustment on DPGIFT |
| Pledge | Recurring-gift schedule (RECORD_TYPE='P'); payments are separate RECORD_TYPE='G' gifts linked via PLINK |
| Split Gift | A gift split across designations: Main (M) + children (G with GLINK→Main, SPLIT_GIFT='Y') |
| Soft Credit | A "credit" gift (RECORD_TYPE='S') with GLINK→actual gift |
| Adjustment | 3-record chain: Original (A) + Adjustment (H) + Resulting (G/C/J), linked via GLINK/ALINK |
| Contact | Activity / task / interaction record on DPCONTACT |
| Other Info | Generic dated record on DPTHERINFO (anchor for arbitrary UDFs) |
| Tribute | "In Honor Of" / "In Memory Of" designation with recipients and gift associations |
| Flag | A simple boolean tag on the donor (Main tab) — uses DPCODES with FIELD_NAME='FLAG' |
| Checkbox field | Multi-value selection (e.g., Donor Interests) stored as rows in DPUSERMULTIVALUES |
| UDF (User Defined Field) | Custom field on donor / gift / contact / other / address — typed C/D/N |
| EFT Payment Method | Stored payment method on DPPAYMENTMETHOD, tied to SafeSave Customer Vault |
Common Patterns
Pagination Around the 500-Row Limit
SELECT TOP 500 code, description FROM dpcodes
WHERE field_name='SOLICIT_CODE' AND code > '{last code}'
ORDER BY code
Delta Sync — Recent Gift Changes
SELECT TOP 500 gift_id, amount, created_date, modified_date, gl_code
FROM dpgift
WHERE COALESCE(DPGIFT.MODIFIED_DATE, DPGIFT.CREATED_DATE) >= '{date}'
AND gift_id > {last_gift_id}
ORDER BY gift_id
COALESCE returns modified_date if non-null, otherwise created_date — so new and modified gifts both come through.
Created / Modified Audit Fields
Not directly writable, but populated automatically:
@user_id→created_byon new records,modified_byon updates to existing recordscreated_date→ today on new recordsmodified_date→ today on updates to existing records
Soft Credits
A soft credit recognizes Donor B for a gift that Donor A actually made.
RECORD_TYPE = 'S'
DONOR_ID = <recognized donor>
GLINK = <gift_id of the actual gift>
AMOUNT = <same as actual gift>
Create with dp_savegift with @record_type='S' and @glink=<actual gift_id>.
Split Gifts
A split gift divides one transaction across multiple designations (e.g., $100 split $75 Building Fund / $25 General).
| Role | record_type | split_gift | glink | Financial fields |
|---|---|---|---|---|
| Main (header) | M |
N |
(none) | Set to literal 'SEE_SPLIT': @gl_code='SEE_SPLIT', @solicit_code='SEE_SPLIT', etc. |
| Each child | G |
Y |
<Main gift_id> |
Real code values |
Create Main first, then each child with glink=<main gift_id>.
Pledges & Pledge Payments
- Create the parent pledge with
dp_savepledge—RECORD_TYPE='P',@total,@bill,@frequency(M/Q/S/A). - For EFT auto-processing, set the parent pledge's
DPGIFTUDF.EFT='Y'usingdp_save_udf_xml:action=dp_save_udf_xml¶ms=@matching_id={pledge gift_id}, @field_name='EFT', @data_type='C', @char_value='Y', @date_value=null, @number_value=null, @user_id='MyApp' - Populate
@vault_idon the pledge with the SafeSave Vault ID — required for the pledge to be active. - Create a payment method via
dp_PaymentMethod_Insert(after creating the SafeSave Customer Vault ID). - Subsequent pledge payments are regular gifts (
dp_savegiftwith@record_type='G',@pledge_payment='Y',@plink=<parent pledge gift_id>) — or DP processes them automatically via EFT once set up.
Gift Adjustments (e.g., Refunds)
DonorPerfect represents an adjustment as a three-record chain:
| Role | record_type | gift_id | gift_date | amount | Links |
|---|---|---|---|---|---|
| Original | A (was G) |
existing | original date | original amount | — |
| Adjustment | H |
new | today | delta (negative for refund) | glink=original gift_id |
| Resulting | G (or C/J if reduced to 0) |
new | original date | new amount | alink=original gift_id |
Workflow:
- SELECT existing gift to capture all field values.
- Update original gift via
dp_savegiftsetting@record_type='A'(everything else unchanged). - Create Adjustment gift via
dp_savegiftwith delta amount and@glink. - Create Resulting gift via
dp_savegiftwith new amount,@alink, andgift_narrativeappended.
If the original gift had UDF or other extra field data, the Resulting gift should mirror it.
Checkbox Fields vs. Flags
These are NOT the same — keep them separate:
| Checkbox Fields | Flags | |
|---|---|---|
| Stored in | DPUSERMULTIVALUES |
DPFLAGS |
| UI location | Bio / Other tabs (e.g., Donor Interests) | Main tab top |
| Set | mergemultivalues (preferred) |
dp_saveflag_xml |
| Unset/replace | mergemultivalues (omit codes to unset) |
dp_delflags_xml (deletes ALL flags only) |
| Field types | Per-field (FIELD_NAME in DPUSERMULTIVALUES) |
Single field with FIELD_NAME='FLAG' in DPCODES |
Reading currently-set checkbox values:
SELECT field_name, matching_id, code FROM dpusermultivalues
WHERE field_name='DONINTS' AND matching_id={donor_id}
Reading currently-set flags:
SELECT * FROM dpflags WHERE donor_id={donor_id}
Discovering valid codes for a field:
SELECT code, description FROM dpcodes WHERE field_name='{field name}'
Tributes Workflow
To add a tribute and notify a recipient about one specific gift:
- Lookup or create the tribute. Use
dp_tribAnon_Searchto find existing, ordp_tribAnon_Createwith@DPCodeIDfromSELECT CODE, CODE_ID, DESCRIPTION FROM DPCODES WHERE FIELD_NAME='MEMORY_HONOR'(typically707=In Honor Of,708=In Memory Of). - Associate to the gift with
dp_tribAnon_AssocTribsToGift. - Add a recipient for this gift with
dp_tribAnon_SaveTribRecipient(named-parameter syntax required). - Create the notification record with
dp_tribNotif_Save— most fields mirror the original gift; markers are@gift_type='SN',@record_type='N',@ty_letter_no='NT'.
To update the recipient list for ALL gifts on a tribute, use dp_tribAnon_Update — but you MUST include existing recipients or they'll be removed:
SELECT r.tributeid, t.name, r.donor_id, r.createddate, t.activeflg
FROM dptributesanon t, dptributesanon_recipients r
WHERE t.tributeid = r.tributeid AND t.tributeid = {desired tributeid}
Then call with @recipients=N'105|43256|323387|137' (pipe-delimited, N-prefixed).
User Defined Fields (UDFs)
dp_save_udf_xml writes to whichever UDF table matches your @matching_id:
| @matching_id | Table written |
|---|---|
| donor_id | DPUDF |
| gift_id | DPGIFTUDF |
| contact_id | DPCONTACTUDF |
| other_id | DPTHERINFOUDF |
| address_id | DPADDRESSUDF |
Set ONE of @char_value / @date_value / @number_value based on @data_type (C/D/N); set the other two to null. The UDF field must already exist in the DP system (Code Maintenance > Field Definitions).
Codes (DPCODES) — Drop-Down Values
All coded fields (GL Code, Solicit Code, Campaign, Memory/Honor, Flag, Address Type, Donor Type, etc.) draw their valid values from DPCODES.
SELECT code, description FROM dpcodes WHERE field_name='{FIELD_NAME}'
Add/update via dp_savecode. Behavior of @original_code:
| Condition | Result |
|---|---|
@original_code=@code AND code exists |
UPDATE the existing code |
@original_code=NULL AND code exists |
Returns '2', no change |
@original_code=NULL OR @original_code=@code AND code does NOT exist |
CREATE new code |
Set @inactive='N' to ensure the code shows in UI dropdowns.
Multi-Currency
Pass @currency='USD' / 'CAD' / etc. on dp_savegift and dp_savepledge. If omitted on a pledge, defaults to USD.
Receipt Delivery (@receipt_delivery_g)
| Code | Meaning |
|---|---|
N |
Do not acknowledge |
E |
Email only |
B |
Email and letter |
L |
Letter only |
Canadian sites also have @acknowledgepref: 1AR (Ack+Receipt), 2AD (Ack/no Receipt), 3DD (no Ack/no Receipt).
UK Gift Aid
DP includes these fields for the UK Gift Aid tax incentive program:
| Table | Field | Purpose |
|---|---|---|
| DP | GIFT_AID_ELIGIBLE |
'Y'/'NO' — donor eligibility |
| DPUDF | GA_TITLE |
Title used on gift aid charity donation |
| DPUDF | GA_ADDRESS |
Foreign (non-UK) address textbox |
| DPGIFT | GIFT_AID_ELIGIBLE_G |
'Y'/'N' — gift eligibility |
| DPGIFT | GIFT_AID_DATE |
Date submitted to HMRC |
| DPGIFT | GIFT_AID_AMT |
Portion eligible for tax relief |
| DPTHERINFO | GA_START_DT |
Declaration start |
| DPTHERINFO | GA_END_DT |
Declaration end |
| DPTHERINFO | GA_DECL_ACTIVE |
'Y'/'N' — declaration active |
Quebec Law 25 (Privacy & Consent)
Stored as UDFs — must be present in the DP system before writing. Test first:
SELECT DISTINCT field_name FROM sd_field
WHERE field_name LIKE 'PM_%' OR field_name LIKE 'PO_%'
PM_* fields live on DPUDF (Main); PO_* fields live on DPTHERINFOUDF (Other Info):
| Table | Field | Purpose |
|---|---|---|
| DPUDF | PM_CONSENT |
Consent given (Yes/No) |
| DPUDF | PM_CONSENT_DT |
Actual consent date |
| DPUDF | PM_CONSENT_EXPIRY |
Actual consent expiry date |
| DPUDF | PM_DELETE |
Erasure requested (Yes/No) |
| DPUDF | PM_DELETE_DT |
Erasure requested on |
| DPTHERINFOUDF | PO_CONSENT, PO_CONSENT_DT, PO_CONSENT_EXPIRY, PO_DELETE, PO_DELETE_DT, PO_EXPORT_DT, PO_NOTES |
Per-event privacy/consent profile |
Save via dp_save_udf_xml with @matching_id=@donor_id for PM_* and @matching_id=@other_id for PO_*.
Unicode
DP systems must be Unicode-enabled by Support to store UCS-2/UTF-16. Then prefix strings with N:
@first_name=N'Phúc cho những người'
Gotcha:
dp_save_udf_xmldoes NOT currently support Unicode via the=N'xxx'syntax — Unicode characters land as?. Workaround: contact DP API Desk.
URL Encoding Example (PHP)
$preamble = "https://www.donorperfect.net/prod/xmlrequest.asp?apikey=";
$key = "xxxxxxxxxxxxxxxxxx";
$action = "&action=dp_save_udf_xml¶ms=";
$payload = "@matching_id=640, @field_name='MRWMEMO', @char_value='Basic math = 5',
@date_value=null, @number_value=null, @user_id='APITestCall'";
$encoded_APIcall = $preamble . $key . $action . urlencode($payload);
The apikey appears BEFORE urlencode(); only the payload is encoded.
Full Reference
For complete parameter tables, edge cases, and original sample calls, the PDF and structured JSON are in references/:
references/procedures.json # All 25 procedures with full parameter tables
references/tables.json # All DP tables with column lists and notes
references/DPO_SUP_Manual_XML_API_Documentation050324.pdf # Source v7.1 (May 2024)
Search patterns:
- All procedures:
jq '.procedures | keys' references/procedures.json - One procedure:
jq '.procedures.dp_savegift' references/procedures.json - All tables:
jq '.tables | keys' references/tables.json - Table columns:
jq '.tables.DPGIFT.key_columns' references/tables.json - PDF deep dive:
Read references/DPO_SUP_Manual_XML_API_Documentation050324.pdfwith a pages range
Support
| Channel | Detail |
|---|---|
| API Help Desk | api@softerware.com (Mark Warren, XML API Consultant) |
| Phone | 1-888-637-7745 |
| Hours | Mon–Fri 8:30am–5:00pm EST |
| Emergencies | Additional email to support@donorperfect.com |
API support covers: call syntax, recommendations, error explanations, restoring API service after DP outages. It does NOT cover: writing/debugging your application, creating custom docs, or any work on code outside the DP API itself.
Disclaimer
This skill is not affiliated with, endorsed by, or sponsored by SofterWare or DonorPerfect. It references publicly available API documentation for educational and integration purposes. The information may be outdated or incomplete — always refer to the official DonorPerfect documentation and release notes for the most current API specifications. Field availability (e.g., Quebec Law 25 UDFs, Unicode, EFT) depends on per-client configuration and add-ons; always test for field presence before writing.