HubSpot

Sync donors as Contacts and donations as Deals.

Overview

The HubSpot integration syncs Donately donor and donation data to HubSpot Contacts and Deals. You can configure which pipeline and deal stage donations are assigned to, including separate stages for recurring donations.

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
  • Deal — Each donation, assigned to a configurable pipeline and deal stage

Configuration

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

Pipeline
SettingDescription
pipelineHubSpot pipeline name where donation deals are created
pipeline_idHubSpot pipeline UUID
Deal Stages
SettingDescription
deal_stageDeal stage assigned to one-time donations (e.g., "Closed Won")
deal_stage_idHubSpot deal stage UUID for one-time donations
recurring_deal_stageDeal stage assigned to recurring donations (e.g., "Pledged")
recurring_deal_stage_idHubSpot deal stage UUID for recurring donations

Field Mapping

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

Contact

Donately FieldHubSpot Native PropertyDonately Custom PropertyCustom Property Deprecating Soon
emailemail
first_namefirstname
last_namelastname
unique_identifierdntly_donor_id
full_addressdntly_full_address
street_address + street_address_2address (combined)dntly_donor_street / dntly_donor_apartmentx
citycitydntly_donor_cityx
statestatedntly_donor_statex
zip_codezipdntly_donor_zipx
countrycountrydntly_donor_countryx
phone_numberphonedntly_donor_phonex

Deal (Donation)

Donately FieldHubSpot Native PropertyDonately Custom Property
(literal) "Donately Donation"dealname
donation_amountamount
currency_codedeal_currency_code
unique_identifierdntly_donation_id
donation_datedntly_donation_date
statusdntly_donation_status
transaction_iddntly_donation_transaction_id
processordntly_donation_processor
donation_typedntly_donation_type
anonymousdntly_donation_anonymous
on_behalf_ofdntly_donation_on_behalf_of
commentdntly_donation_comment
recurringdntly_donation_recurring
subscription_frequencydntly_subscription_frequency
subscription_iddntly_subscription_id
subscription_statusdntly_subscription_status
subscription_start_daydntly_subscription_start_day
campaign_iddntly_donation_campaign_id
campaign_titledntly_donation_campaign_title
fundraiser_iddntly_donation_fundraiser_id
fundraiser_titledntly_donation_fundraiser_title
form_iddntly_donation_form_id
donor_iddntly_donor_id
livemodedntly_donation_livemode
tracking_codesdntly_donation_tracking_codes
metadatadntly_donation_meta_data
ecarddntly_donation_ecard
notesdntly_donation_notes
dtd_company_namedntly_donation_dtd_company_name

Record Matching

When syncing data, the integration uses a series of strategies to find existing records in HubSpot before creating new ones. Strategies are tried in order — the first match wins.

Contact Matching

StrategyHow It Works
FindByPersonIdSearches for a contact by the dntly_donor_id custom property. This is the primary strategy and matches contacts created by the native integration.
FindByEmailFalls back to searching by the contact's email field. Used when dntly_donor_id is not found (e.g., contacts created manually or by another tool).

Deal Matching

StrategyHow It Works
FindByDonationIdSearches for a deal by the dntly_donation_id custom property. This is the primary strategy and matches deals created by the native integration.
FindByCompositeMatchFalls back to matching by a combination of the associated contact's email, deal amount, and close date. Only targets deals that do not have dntly_donation_id set. Used to match legacy records synced via Zapier or other tools that did not include the Donately Donation ID. If multiple deals match the same criteria, the match is skipped and a new deal is created instead — the ambiguous match is flagged for manual review in the Donately dashboard so you can merge duplicates in HubSpot if needed. When a single match is found, all native fields (including dntly_donation_id) are backfilled on the next update, so subsequent syncs use the faster primary strategy automatically.
The composite match strategy is designed for one-time migration scenarios. Once a legacy deal is matched and updated with the Donately Donation ID, all future syncs for that donation will use the primary FindByDonationId strategy.

Advanced

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 (or helper expressions) and values are the target HubSpot property names.

{
  "Person": {
    "email": "email",
    "unique_identifier": "dntly_donor_id",
    "phone_number": "phone"
  },
  "Donation": {
    "donation_amount": "amount",
    "comment": "dntly_donation_comment"
  }
}
  • Person — Maps donor fields to HubSpot Contact properties
  • Donation — Maps donation fields to HubSpot Deal properties
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 key side of a mapping entry can use a helper expression to compute or transform the value written to HubSpot.

ExpressionDescriptionExample
custom_string:<value> Writes a literal string to the HubSpot property regardless of donation data. "custom_string:Online Donation": "hs_deal_source" → writes "Online Donation" to hs_deal_source
{
  "Donation": {
    // Literal string — always write "Online" to hs_deal_source
    "custom_string:Online": "hs_deal_source"
  }
}

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) → HubSpot Contact
FieldReturnsNotes
Identity & name
emailDonor email addressPrimary key for matching
unique_identifierDonately Person IDStable, globally unique
first_nameRaw first name as enteredUsed by default mapping
last_nameRaw last name as enteredUsed by default mapping
full_name"{first_name} {last_name}"Use this for a single “donor name” custom property
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
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
Donation → HubSpot Deal
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)
donation_date_for_native_integrationsUnix epoch millisecondsDefault mapping uses this; HubSpot date fields expect ms
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?Boolean — same as recurringDefault mapping uses this
refunded? / refundedBoolean — has been refunded
refunded_atRefund timestamp
Content
donation_description_for_native_integrations"$25 Donation to {campaign} {fundraiser}"
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
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
Misc
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.