Salesforce

Full CRM sync — Contacts, Accounts, and Opportunities.

Overview

The Salesforce integration syncs Donately donor and donation data to Salesforce Contacts, Accounts, and Opportunities. It supports both single-account and household-account models, and can associate donations with Salesforce Campaigns.

The integration connects via OAuth. Once connected, syncs are triggered automatically each time a donation is created, updated, or refunded in Donately.

What Gets Synced

  • Contact — Donor identity and address information
  • Account — Donor's associated account (single or household model)
  • Opportunity — Each donation, including recurring subscription details
  • Campaign — Donations can be associated with a Salesforce Campaign (optional)

Configuration

These settings are configured per Donately account and control how records are created and linked in Salesforce.

Integration User
SettingDescriptionDefault
user_id18-character Salesforce User ID used for API calls and record ownership
Account Mapping
SettingDescriptionDefault
account_modelHow Accounts are created and associated with Contacts:

single — All contacts share one default Account, created once during initialization.
household — Each contact gets a dedicated Account named by the household_name_format template (NPSP-style).
none — Donately does not create or assign Accounts. Salesforce or NPSP automation handles account creation.
single
household_name_formatTemplate for household Account names when account_model is household. Supports {first_name} and {last_name} tokens.{last_name} Household
account_record_type_idSalesforce Record Type ID applied to new Accounts
Contact Mapping
SettingDescriptionDefault
contact_roleRole assigned to the Contact on the Opportunity Contact Role (e.g., "Donor")
contact_record_type_idSalesforce Record Type ID applied to new Contacts
Opportunity Mapping
SettingDescriptionDefault
donation_stage_nameOpportunity stage for one-time donationsClosed Won
recurring_donation_stage_nameOpportunity stage for recurring donationsPledged
opportunity_record_type_idSalesforce Record Type ID applied to new Opportunities
gift_type_fieldCustom field API name to store the gift type on the Opportunity
gift_type_valueValue written to gift_type_fieldDonately
source_fieldCustom field API name to store the donation source on the Opportunity
source_value_fromTemplate for the source value. Supports template tokens like {campaign_title}.
fund_fieldCustom field API name to store the fund/designation on the Opportunity
fund_default_valueDefault value written to fund_fieldGeneral Operating
Campaign Mapping — optional

When configured, donations are associated with a matching Salesforce Campaign based on campaign rules. See Campaign Rules for how matching works.

SettingDescriptionDefault
campaign_member_statusStatus assigned to the Contact when added as a Campaign Member (e.g., "Responded")

Field Mapping

Default mappings from Donately fields to Salesforce fields. These can be overridden using custom field mapping.

Contact

Donately FieldSalesforce Field
emailEmail
first_nameFirstName
last_nameLastName
unique_identifierdntly_PersonId__c
phone_numberPhone
street_addressMailingStreet
cityMailingCity
stateMailingState
zip_codeMailingPostalCode
countryMailingCountry
full_addressdntly_FullAddress__c

Account

Donately FieldSalesforce Field
titleName
unique_identifierdntly_AccountId__c

Opportunity (Donation)

Donately FieldSalesforce Field
donation_nameName
donation_amountAmount
donation_dateCloseDate
donation_descriptionDescription
unique_identifierdntly_DonationId__c
currencydntly_Currency__c
donation_typedntly_DonationType__c
transaction_iddntly_TransactionId__c
processordntly_Processor__c
livemodedntly_Livemode__c
anonymousdntly_Anonymous__c
on_behalf_ofdntly_OnBehalfOf__c
commentdntly_Comments__c
statusdntly_DonationStatus__c
recurringdntly_DonationRecurring__c
subscription_frequencydntly_RecurringFrequency__c
subscription_iddntly_SubscriptionId__c
subscription_statusdntly_SubscriptionStatus__c
subscription_start_datedntly_SubscriptionStartDate__c
campaign_iddntly_CampaignId__c
campaign_titledntly_CampaignName__c
fundraiser_iddntly_FundraiserId__c
fundraiser_titledntly_FundraiserName__c
form_iddntly_FormId__c
account_iddntly_AccountId__c
tracking_codesdntly_TrackingCodes__c
metadatadntly_Metadata__c
dtd_company_namedntly_DtdCompanyName__c

Campaign Rules

Campaign rules allow you to route donations to specific Salesforce Campaigns based on matching criteria. Rules are evaluated in order — the first match wins.

Rule Types

TypeDescription
formMatch by the Donately Form used for the donation
campaignMatch by the Donately Campaign the donation was made to
fundraiserMatch by the Donately Fundraiser the donation was made through
meta_dataMatch by a metadata key/value on the donation
auto_create_from_campaignAutomatically create a Salesforce Campaign from the Donately campaign
auto_create_from_fundraiserAutomatically create a sub-campaign from the Donately fundraiser under the parent campaign
fallback_campaignDefault catch-all rule if no other rules match

Rule Structure

{
  "type": "campaign",
  "match_value": "cmp_e4b08ef12147",
  "match_label": "Annual Giving Campaign",
  "sf_campaign_id": "7013t000001ABC",
  "sf_campaign_name": "2025 Annual Fund"
}
Rules are evaluated in order from top to bottom. Place your most specific rules first and the fallback rule last. Only one fallback rule and one auto-create rule are recommended.

Duplicate Detection

When Salesforce's duplicate detection rules fire during a Contact create or update, the integration automatically handles the DUPLICATES_DETECTED error by retrying with Salesforce's allowSave header. The contact is saved successfully and the potential duplicates are flagged for manual review in the Donately dashboard.

This means your Salesforce duplicate rules will never block syncs from Donately, but you'll still be alerted to potential duplicates so you can merge records as needed.

Account Creation by Account Model

How Accounts are created and associated with the Contact depends on the account_model setting:

account_modelAccount Behavior
single One shared Account is created (or found) once during integration setup and reused for all Contacts and Opportunities. The Contact's AccountId is always set to this single Account.
household A dedicated Account is created per Contact, named using the household_name_format template (e.g., "Smith Household"). If a household Account for that donor already exists it is reused. The Contact's AccountId is set to this household Account, and the Opportunity is linked to it as well.
none Donately does not create or assign any Account. The Contact's AccountId is left unset, allowing Salesforce flows or NPSP automation to assign it. For Opportunities, if the Contact has no AccountId at sync time, the Opportunity's account association is also left unset.
Use account_model: none if your Salesforce org uses NPSP or custom automation to manage Account creation. Donately will sync the Contact and Opportunity without interfering with your existing Account assignment logic.

Advanced

Template Tokens

Some configuration fields support dynamic tokens that are replaced with actual values at sync time:

TokenResolves ToUsed In
{first_name}Donor's first namehousehold_name_format
{last_name}Donor's last namehousehold_name_format
{campaign_title}Donately campaign titlesource_value_from
{fundraiser_title}Donately fundraiser titlesource_value_from
{fundraiser_or_campaign_title}Fundraiser title if present, otherwise campaign titlesource_value_from
// Household name format
"{last_name} Household"
// Resolves to: "Smith Household"

// Source value from campaign
"Online - {campaign_title}"
// Resolves to: "Online - Annual Giving 2025"

Custom Field Mapping

You can override the default field mappings with a custom mapping. Custom mappings are defined as a JSON object where keys are Donately field names and values are either a Salesforce field API name or a helper expression.

{
  "Person": {
    "email": "Email",
    "unique_identifier": "dntly_PersonId__c",
    "phone_number": "MobilePhone"
  },
  "Donation": {
    "donation_amount": "Amount",
    "comment": "My_Custom_Comments__c"
  }
}
  • Person — Maps donor fields to Salesforce Contact fields
  • Donation — Maps donation fields to Salesforce Opportunity fields
Custom mappings are merged with the defaults. You only need to specify the fields you want to override — any fields not listed in your custom mapping will use the default mapping.

Mapping Helper Expressions

Instead of a Donately field name, the value side of a mapping entry can use a helper expression to compute or transform the value written to Salesforce.

ExpressionDescriptionExample
custom_string:<value> Writes a literal string to the Salesforce field regardless of donation data. "custom_string:Online Donation": "My_Source__c" → writes "Online Donation" to My_Source__c
date_format(<format>) Formats the donation's donation_date using a pattern built from yyyy, mm, and dd tokens. Returns nil if no donation date is present. "date_format(yyyy-mm-dd)": "My_Date__c" → writes "2025-03-15" to My_Date__c
donation.meta_data['<key>'] Reads a value from the donation's meta_data hash by key. Returns nil if the key is not present. "donation.meta_data['source_code']": "My_Source__c" → writes the source_code metadata value to My_Source__c
<expr> || <expr> Fallback operator. Tries the first expression; if it returns nil or an empty string, uses the second expression instead. Expressions can be any mapping helper (meta_data, custom_string, method name, etc.). Can be chained for multiple fallbacks. "donation.meta_data['honoree_name'] || donation.meta_data['cf_text_2_3']": "dntly_OnBehalfOf__c" → uses honoree_name if present, otherwise falls back to cf_text_2_3
{
  "Donation": {
    // Literal string — always write "Online" to My_Channel__c
    "custom_string:Online": "My_Channel__c",

    // Date format — write donation date as "2025-03-15"
    "date_format(yyyy-mm-dd)": "My_CloseDate__c",

    // Metadata — pull a custom source_code passed on the donation
    "donation.meta_data['source_code']": "My_Source__c",

    // Fallback — try honoree_name first, fall back to cf_text_2_3
    // Useful when multiple forms write tribute data to different meta_data keys
    "donation.meta_data['honoree_name'] || donation.meta_data['cf_text_2_3']": "dntly_OnBehalfOf__c"
  }
}

Available Donately Fields

The tables below list the Donately fields that can be used as keys in a custom mapping. Any public method on the underlying record is accepted — these are the ones most commonly useful for CRM sync.

Person (donor) → Salesforce Contact
FieldReturnsNotes
Identity & name
emailDonor email addressPrimary key for matching
unique_identifierDonately Person IDStable, globally unique
first_nameRaw first name as entered
last_nameRaw last name as entered
first_name_for_native_integrationsSame as first_nameDefault mapping uses this; safe to swap with first_name
last_name_for_native_integrationsSame as last_nameDefault mapping uses this
full_name"{first_name} {last_name}"Use this for a single “donor name” custom field
nameAlias of full_name
full_name_or_emailfull_name if present, otherwise emailSafe fallback when names may be blank
first_name_or_emailfirst_name if length > 2, otherwise email
first_name_cleanTitleized first_name, “ And ” → “ and ”Normalizes ALL-CAPS / all-lowercase entries
last_name_cleanTitleized last_name
Contact
phone_numberRaw phone as entered
phone_number_formattedFormatted phone (e.g. (555) 123-4567)
Address
street_addressStreet line 1
street_address_2Street line 2 (apt/suite)
cityCity
stateState / region
zip_codeZIP / postal code
countryCountry
full_addressAll address fields joined with spacesIncludes blanks
addressAlias of full_address
full_address_for_native_integrationsNon-blank address fields joined with Cleanest single-line address; default mapping uses this
Flags & metadata
newsletterBoolean — opted into newsletter
fundraiserBoolean — has ever created a fundraiser
email_verifiedTimestamp when email was verified (or nil)
created_atWhen the Donately Person record was created
updated_atWhen the Person record last changed
person.meta_data['<key>']Reads a single key from the Person’s meta_data hashHelper expression; returns nil if key missing
Donation → Salesforce Opportunity
FieldReturnsNotes
Identity
unique_identifierDonately Donation ID
transaction_idPayment processor charge IDe.g. Stripe ch_...
Amount & currency
donation_amount_for_native_integrationsAmount as decimal dollars (e.g. 25.00)Default mapping uses this for Amount
amount_in_centsAmount as integer cents
donation_amount_formatted_for_native_integrationsLocale-formatted string (e.g. $25.00)
currencyISO currency code, lowercase (e.g. usd)
currency_code_for_native_integrationsCurrency code upper-cased (e.g. USD)
Date
donation_dateRuby timestamp (UTC)Use date_format(…) helper for string output
donation_date_for_native_integrationsUnix epoch milliseconds
donation_date_in_account_timezoneTimestamp shifted to the account’s timezone
created_atWhen the Donation record was created
Type & status
statuscompleted, failed, refunded, etc.
donation_typeInternal type code (e.g. cc, paypal)
get_donation_typeHuman label (Credit Card, Paypal, …)
processorstripe, paypal, authorize_net
livemodeBoolean — live vs test
anonymousBoolean
recurringBoolean — part of a recurring subscription
recurring_for_native_integrationsForced boolean cast of recurring
refunded? / refundedBoolean — has been refunded
refunded_atRefund timestamp
Content
donation_name_for_native_integrationsVerbose name (e.g. Jane Smith $25.00 One-Time donation on 2026-04-24…)Default mapping uses this for Name
donation_description_for_native_integrations"$25 Donation to {campaign} {fundraiser}"Default mapping uses this for Description
donation_name / nameDonor full name (or ANONYMOUS / tribute name)
commentDonor’s comment
notesInternal notes
on_behalf_ofTribute / honoree name
dumpRaw tracking-code dump from the form
originOriginating page URL
clean_originURL-unescaped origin
ecardE-card JSON (if used)
metadata_for_native_integrationsHTML-unescaped JSON blob of all meta_data
donation.meta_data['<key>']Reads a single key from the donation’s meta_dataHelper expression
Donor (delegated to Person)
email, first_name, last_name, phone_numberDelegated from the donorSame values as on Person
street_address, street_address_2, city, state, zip_code, countryDonor address fields
full_address_for_native_integrationsDonor address as a single space-joined string
Campaign / Fundraiser / Form
campaign_id_for_native_integrationsCampaign’s unique_identifier
campaign_title_for_native_integrationsCampaign title
fundraiser_id_for_native_integrationsFundraiser’s unique_identifier
fundraiser_title_for_native_integrationsFundraiser title
form_id_for_native_integrationsForm’s unique_identifier
Subscription (recurring)
subscription_id_for_native_integrationsSubscription’s unique_identifier
subscription_frequency_for_native_integrationsmonthly, yearly, etc.
subscription_start_day_for_native_integrationsYYYY-MM-DD string
subscription_status_for_native_integrationsSubscription state
Account & misc
donation_account_for_native_integrationsNonprofit account’s unique_identifier
donor_id_for_native_integrationsDonor’s unique_identifier
dtd_company_name_for_native_integrationsDouble-the-Donation matched company name
Any public method on the underlying Ruby record is callable from a mapping key, so a field not listed here may still work. If you need something that isn’t here, reach out to support and we’ll confirm availability or add it.