Appearance
Overview
NOMA Sync receives webhooks from three platforms. Do not call these endpoints directly — they are configured in each platform’s dashboard. This page summarizes what each webhook sends and how NOMA Sync uses it.
Givebutter
Endpoint: POST /webhooks/givebutter
Auth: Signature verification (if GIVEBUTTER_WEBHOOK_SECRET or equivalent is set).
Events
- transaction.succeeded – New donation or ticket purchase. Primary event for syncing to LGL.
- ticket.created – Event ticket purchase (may duplicate or complement transaction.succeeded; see Worker logic).
- campaign.created / campaign.updated – Used to refresh campaign cache for Mappings.
Payload (conceptual)
- Transaction: id, amount, currency, campaign_id, supporter (name, email, phone, address), custom_fields, payment method, created_at.
- Campaign: id, name, type (donation, ticket, peer_to_peer).
NOMA Sync uses: transaction id (idempotency givebutter_{id}), amount, campaign_id/campaign type (for mapping), supporter email/name/phone/address (constituent), custom_fields (LGL custom fields), payment method (gift type).
Square
Endpoint: POST /webhooks/square
Auth: HMAC signature in header; validated with SQUARE_WEBHOOK_SIGNATURE_KEY. Request body must be the raw JSON (no modification by proxy).
Events
- order.created – New order. Synced when state is COMPLETED or OPEN with payment.
- order.updated – Order changed. Worker may fetch full order from Square API; syncs only when state is COMPLETED or OPEN with payment.
Payload (conceptual)
Square often sends a notification object with merchant_id, type, event_id, created_at, and data containing object with order_id (and sometimes a small order snapshot). NOMA Sync uses order_id to fetch the full order (and customer if needed) via Square API.
Key fields (from full order)
- order.id – Idempotency key
square_order_{id}. - order.location_id – Used for location override mapping to LGL fund.
- order.total_money – Gift amount (cents → dollars).
- order.created_at – Gift date.
- order.tenders – Payment type (CARD, CASH, etc.) mapped to LGL payment type.
- order.customer_id – Fetched to get email/name for constituent; if missing, default constituent is used.
Mailchimp
Endpoint: POST /webhooks/mailchimp
Auth: Webhook secret (if MAILCHIMP_WEBHOOK_SECRET or equivalent is set).
Events
- Unsubscribe – Member unsubscribed from a list. NOMA Sync finds constituent in LGL by email and updates tags (e.g. remove “Newsletter”) per tag rules.
- Cleaned – Email cleaned (bounced/invalid). Similar handling: update or remove LGL tag.
Payload (conceptual)
- type – unsubscribe, cleaned, etc.
- data – list_id, email, email_id, merges (FNAME, LNAME), etc.
NOMA Sync uses: list_id (list mapping), email (constituent lookup in LGL), and applies tag rules from Mailchimp Settings.
Idempotency
| Source | external_id format | Purpose |
|---|---|---|
| Givebutter | givebutter_{transaction_id} | Avoid duplicate gifts for same transaction |
| Square | square_order_{order_id} | Avoid duplicate gifts; LGL also enforces external_id |
| Mailchimp | Event-based (no gift) | Audit only; logged to sync_log; duplicate events are safe |
Retries
- Givebutter – Check Givebutter docs for webhook retry policy. NOMA Sync runs backup polling every 15 minutes.
- Square – Square retries failed webhooks (e.g. 5xx). NOMA Sync returns 200 on success or when event is skipped (idempotent).
- Mailchimp – Check Mailchimp docs for retry. Return 200 quickly to avoid duplicate sends.

