> ## 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.

# Neon CRM Configuration Options

> Detailed configuration options and settings for the WeGive Neon CRM integration

# Configuration Options

## Integration Settings

### Authentication Settings

* **Neon Organization ID** and **Neon API Key** — both required; WeGive uses HTTP Basic auth with `organization_id:api_key`
* **Environment**: selected automatically from WeGive's own deployment environment (`api.neoncrm.com` production, `trial.neoncrm.com` staging) — not a setting you choose per organization

### Integration Status

| Setting | What it actually does |
| - | - |
| `enabled` | Master switch. Turning this off also removes any webhooks previously created. |
| `crm_sync` | Gates donor push (`exportDonor`) alongside `enabled` and `track_donors`. Address sync (`syncAddress`) is separately gated by the same flags, but is dead code — see the warning below. |
| `two_way_sync` | Genuinely controls whether webhooks are created/removed on enable/disable — this one works as documented |

### Entity Tracking Options

<Warning>
  Only **two** of the four "tracking" toggles actually gate anything. `track_donors` gates donor, donation, recurring-donation, and address sync (all of them — despite the name suggesting donor-only scope). `track_campaigns` gates campaign sync. **`track_donations` and `track_recurring_donations` are columns on the `neon_integrations` table that are never read anywhere in the sync code** — toggling them has no effect. This is a known issue.
</Warning>

### Sync Direction

<Warning>
  There is no per-entity "Push Only / Pull Only / Bidirectional / Disabled" configuration for this integration. Each object type has a fixed, hardcoded direction in the code:
</Warning>

| Object | Actual direction |
| - | - |
| Donor | Both (push on create/update, pull once daily) |
| Donation | Both |
| Campaign | Both |
| Recurring Donation | **Push only** — no pull-back exists |
| Address | **Dead code — never actually runs.** This is a known issue. |

## Webhook Configuration

When `enabled` and `two_way_sync` are both true, WeGive automatically registers 4 webhooks with Neon:

* `CREATE_ACCOUNT` → `neon-integrations/create-donor`
* `UPDATE_ACCOUNT` → `neon-integrations/update-donor`
* `CREATE_DONATION` → `neon-integrations/create-donation`
* `UPDATE_DONATION` → `neon-integrations/update-donation`

<Warning>
  There is no webhook for recurring donations, campaigns, or addresses — only the 4 above exist. There's also no webhook retry logic on WeGive's side to speak of — WeGive is the receiver here, not the sender, so retry behavior for a failed webhook delivery is entirely Neon's responsibility, not something this integration configures.
</Warning>

Turning `enabled` off (or disabling `two_way_sync` while re-saving) removes the webhooks via `removeWebhooks()`.

## Data Mapping Configuration

### Default Field Mappings

<Warning>
  **None of these default mappings are actually bidirectional.** `NeonMappingRule` records are only ever applied in `generateAccountParams()`/`generateDonationParams()` — both are **push (export)** functions. Pull (`importDonors()`/`importDonations()`/`importCampaigns()` in `SyncNeon.php`) uses a completely separate, hardcoded field list and never consults `NeonMappingRule` at all. So every mapping below is push-only in practice, regardless of what direction it might imply. This is a known issue.
</Warning>

#### Donor/Account Mappings (push-only, in practice)

| WeGive Field | Neon Field |
| - | - |
| `first_name` | `primaryContact.firstName` |
| `last_name` | `primaryContact.lastName` |
| `email_1` | `primaryContact.email1` |
| `email_2` | `primaryContact.email2` |
| `email_3` | `primaryContact.email3` |
| `email_notifications` | `consent.email` |
| `sms_notifications` | `consent.sms` |

#### Donation/Transaction Mappings (push-only, in practice)

| WeGive Field | Neon Field | Level |
| - | - | - |
| `amount` | `amount` | both |
| `created_at` | `date` | both |
| `donor_name` | `donorName` | both |
| `anonymous` | `anonymousType` | both |
| `fee_amount` | `donorCoveredFee` | both |
| `tribute_name` | `tribute.name` | both |
| `payout.paid_at` | `receivedDate` | **export only** (explicitly `level = 'export'` in the seeded default) |

<Note>
  Donation mappings with `level = 'import'` are explicitly filtered **out** of the export payload (`->where('level', '!=', 'import')`), which correctly implies they're meant for pull use — but since pull never consults `NeonMappingRule` at all, an `import`-level mapping currently has no consumer anywhere in the code. It's a dead configuration option in practice, similar in spirit to (though a distinct bug from) the Finding 1 `literal` gap.
</Note>

#### Campaign Mappings

| WeGive Field | Neon Field | Level |
| - | - | - |
| `name` | `name` | export (push) |
| `goal` | `goal` | export (push) |
| `start_date` | `startDate` | export (push) |
| `expiration` | `endDate` | export (push) |
| `total_donated` | `statistics.donationAmount` | pull (this one genuinely is Neon → WeGive, but via the hardcoded `importCampaigns()` fetch, not via `NeonMappingRule` resolution) |
| `number_of_donations` | `statistics.donationCount` | same as above |

### Custom Field Mapping

JSONPath-based mapping is real:

```json theme={null}
{
  "integration_path": "primaryContact.addresses[0].addressLine1",
  "wegive_path": "mailingAddress.address_1",
  "crm": "NEON",
  "integration": "ACCOUNT"
}
```

<Warning>
  The `literal` flag (meant to send a fixed value instead of resolving `wegive_path` as JSONPath) is **not yet honored** for Neon — every mapping rule is resolved as a JSONPath lookup regardless. This is a known issue, with a fix in review. The `custom` and `create_only` flags are similarly not read by Neon's field-application code.
</Warning>

## Payment Method Configuration

<Warning>
  This is not user-configurable — the tender-type and card-type maps below are hardcoded in `NeonIntegration.php`, not something you can change per organization.
</Warning>

| WeGive Source Type | Neon Tender Type |
| - | - |
| `card` | Credit Card Offline |
| `bank` | Check |
| `donor` | Check |
| anything else | Check (fallback) |

| WeGive Card Type | Neon Card Code |
| - | - |
| `visa` | V |
| `mastercard` | M |
| `amex` | A |
| `discover` | D |

## Address Management

<Warning>
  **`syncAddress()` is dead code — it's never actually called anywhere in the codebase.** This is a known issue. The gating description below (`track_donors`/`enabled`/`crm_sync`) is accurate to the code inside `syncAddress()` itself, but irrelevant since nothing invokes it.
</Warning>

* Address sync (`syncAddress()`) exists as a fully-implemented, separate push path from the donor account, but has no caller — it never runs
* There's no pull for addresses regardless
* On the donor **account** push (`generateAccountParams()`, the only address data that actually reaches Neon today), mailing address is always included; billing address is included too, but only for individual donors — there's no check for whether it differs from the mailing address, both are sent whenever both exist. This inline copy has no phone/fax fields.

## Error Handling and Logging

<Warning>
  There is no automatic retry, no rate-limit throttling, no queue-based batch processing, and no built-in "sync simulator"/"mapping tester"/"connection tester" diagnostic tools for this integration. Every API call is a single unretried `Http::timeout(120)` request. Failures surface via the standard WeGive integration log and Sentry, not via any Neon-specific dashboard tooling.
</Warning>

## Compliance

<Warning>
  There are no GDPR-specific compliance features, configurable data-retention policies, or export-control features implemented specifically for this integration. `consent.email`/`consent.sms` map WeGive's own communication-preference flags to Neon's consent fields — that's the extent of consent handling.
</Warning>

## Configuration API

Real routes (all under the authenticated dashboard API, `integration-permission` middleware):

* `GET /neon-integration` — retrieve the organization's Neon integration settings
* `PUT /neon-integration` — update settings
* `POST /neon-integration/sync` — trigger a manual sync
* `POST /neon-mapping-rules` — create/update field mapping rules (same endpoint handles both, based on whether an `id` is present in the payload)
* `DELETE /neon-mapping-rules/{neon_mapping_rule}` — remove a mapping rule

<Note>
  There is no per-integration `DELETE` route — disabling is done via `PUT /neon-integration` with `enabled: false`, not by deleting the integration record. There is also no `GET /neon-mapping-rules` list-only endpoint distinct from the settings response — mapping rules come back as part of the organization/integration payload.
</Note>

## Troubleshooting Configuration

### Common Issues

* **Authentication errors**: verify both Organization ID and API key
* **Literal mapping rules not working**: known gap, in review
* **Webhook failures**: only 4 webhook types exist (donor/donation create/update) — don't expect one for recurring donations or campaigns
* **Payment method looks wrong in Neon**: expected for anything other than card/bank/donor source types — see the payment method table above

## Support and Resources

* [Data Mapping Overview](/external/onboarding/neon/data-mapping/overview)
* [Integration Nuances](/external/onboarding/neon/integration-nuances)
* WeGive Support: [support@wegive.com](mailto:support@wegive.com)


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