> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wegive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration Nuances

> Free-tier pipeline limits, rate limiting, deduplication, webhooks, and stage mapping for the WeGive HubSpot integration

## Pipeline limit on HubSpot free tier

HubSpot's free tier permits one Deal pipeline. When WeGive provisions on a free account it cannot create separate Donations, Recurring Donations, and Soft Credits pipelines — all three normally get their own pipeline on a paid tier.

* WeGive detects the limit and adds each pipeline's stages to the account's single existing (default) pipeline instead.
* One-time, recurring, and soft-credit deals all land in that one pipeline; stage mapping still works, since WeGive tracks stage IDs per-purpose regardless of which pipeline they live in.
* Re-provisioning is idempotent and label-matching: if a pipeline with the expected label (e.g. "Donations") already exists — including one WeGive itself created earlier — its stages are found and missing ones backfilled, rather than creating a duplicate.
* Upgrade your HubSpot tier and click **Provision** again to gain the three dedicated pipelines.

## Rate limiting

WeGive uses HubSpot's batch endpoints (up to 100 records per call). On a 429 response, WeGive retries with backoff automatically — no action is required. HubSpot's `ten_secondly_rolling` rate-limit responses rarely include a usable `Retry-After` header, so rather than depending on one, WeGive waits at least 10 seconds before retrying (matching HubSpot's own 10-second rolling-bucket reset window) regardless of what the response does or doesn't specify.

## Deduplication

* On push, WeGive locks each record for the duration of the push so concurrent edits do not create duplicates.
* If HubSpot returns 409 Conflict (a Contact already exists with that email), WeGive reads the existing HubSpot ID from the response and links it to the WeGive record instead of creating a duplicate.
* On pull, supporters are matched in this order: HubSpot ID, then the `wegive_id` custom property, then email. Email is the fallback so Contacts created outside WeGive still link cleanly.

## Currency

WeGive stores amounts in cents. Amounts are divided by 100 before pushing, so a \$50.00 gift appears as 50 on the deal.

## ACH handling

By default, ACH transactions still processing sync to HubSpot as Attempted. If your team treats ACH as cleared once initiated, turn on **Send processing ACH as success** in [Configuration Options](/external/onboarding/hubspot/configuration-options#sync-behavior). Those deals push as Success and update to Failed if the ACH later fails.

## Webhooks: deletions and merges

WeGive subscribes to HubSpot webhooks for deletion and merge events: `contact.deletion`, `contact.privacyDeletion`, `company.deletion`, `deal.deletion`, `contact.merge`, and `company.merge`.

* Contact, Company, and Deal deletions in HubSpot do not delete WeGive records. WeGive is the source of truth for supporters.
* WeGive clears the HubSpot ID on the corresponding record so the next push re-creates it cleanly.
* The exception is `contact.privacyDeletion` (GDPR), which deletes the WeGive supporter in compliance with your privacy obligations.
* Merging two Contacts or two Companies in HubSpot reassigns the losing record's data to the WeGive record linked to the winner — each independently toggleable under **Merge handling** in [Configuration Options](/external/onboarding/hubspot/configuration-options#merge-handling), both on by default.

Webhook signatures are validated (HMAC-SHA256, v3). Requests with a timestamp older than five minutes are rejected.

## Pipeline stage mapping

### Donations pipeline

| WeGive transaction status | HubSpot deal stage |
| - | - |
| success, partially refunded | Success |
| processing, pending, retried | Attempted |
| failed, refunded, disputed, cancelled | Failed |

<Note>
  A partially-refunded transaction stays at Success — HubSpot's Donations pipeline has no dedicated partial-refund stage, so it's grouped with fully-successful gifts rather than with Failed. A fully-refunded, disputed, or cancelled transaction all collapse to the same Failed stage.
</Note>

<Warning>
  **Later status changes do move the deal's stage — but asymmetrically to Recurring deals.** On the Donations pipeline specifically, a customer-dragged stage is respected for everything *except* a transaction later going to Failed (refunded, disputed, or cancelled after the fact): that transition always wins, so a gift can't stay stuck showing as a won/Success deal after it's actually failed. This asymmetry exists because the Donations pipeline only has 3 fully-WeGive-derived stages, while the Recurring pipeline's 9 stages are genuinely customer-managed — there, any terminal stage a customer sets wins outright, with no override. If a deal predates this behavior (pre-2026-09-28) and looks stale, ask engineering whether a manual per-org repush has been run for that account — it isn't automatic.
</Warning>

### Recurring Donations pipeline

| WeGive recurring plan status | HubSpot deal stage |
| - | - |
| active | Active |
| paused | Paused |
| cancelled | Cancelled |
| ended | Ended |
| in arrears | In Arrears |
| missing | Missing |
| archived | Archived |
| expiring\_soon | Expiring Soon |
| ending\_soon | Ending Soon |

## Marketing Contacts

WeGive does not distinguish between HubSpot Marketing Contacts and regular Contacts. All supporters push as standard Contacts; marketing contact status is managed inside HubSpot.

## Deal naming

Deal names follow a consistent format so they are scannable in HubSpot (note: the separator is an en dash `–`, not a hyphen):

* One-time: `{Donor Name} – ${Amount} – {Fund Name}`
* Recurring: `{Donor Name} – ${Amount}/{Frequency} – {Fund Name}`
* Soft credit: `{Donor Name} – ${Amount} – Soft Credit`

If no fund is set on the gift, the fund segment is omitted (one-time and recurring only — soft-credit deal names always end in "Soft Credit").

## Associations require both records

A deal associates to a Contact or Company only once both records exist in HubSpot. If you see deals with no associated Contact:

1. Check that the supporter has a HubSpot ID in WeGive (the push completed).
2. Wait for the next sync; the deal associates on its next push.

This is intentional. It avoids orphaned deals during the brief window between pushing a transaction and its supporter.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.