Metadata field
referrer
Source: Stored incoming ?ref= value from localStorage
Buttondown target: Subscriber metadata key: referrer
Validation: Accept only 3-80 characters matching letters, numbers, underscore or hyphen.
Buttondown referral wiring
Implementation contract for wiring Good Morning Cambridge referral attribution into Buttondown without touching live subscribers before approval.
Do not create subscribers, send emails, publish leaderboards, trigger rewards or alter Buttondown settings until the editor approves the live wiring pass. Do not create subscribers, send email, publish named leaderboard rows, trigger rewards or write to Buttondown from this file.
Fields to preserve when replacing the static form with the approved Buttondown embed or API route.
Metadata field
Source: Stored incoming ?ref= value from localStorage
Buttondown target: Subscriber metadata key: referrer
Validation: Accept only 3-80 characters matching letters, numbers, underscore or hyphen.
Metadata field
Source: Browser-local invite token generated by referral.js
Buttondown target: Subscriber metadata key: reader_token
Validation: Generate locally for share links; replace with Buttondown subscriber ID once webhook confirms the reader.
Metadata field
Source: Static subscribe form hidden tag
Buttondown target: Subscriber tag or metadata: website
Validation: Keep source labels boring and stable for campaign reporting.
Metadata field
Source: Launch conversion links and approved social posts
Buttondown target: Subscriber metadata key: utm_campaign
Validation: Only use approved campaign names; no live ad spend without approval.
Events needed before referral counts become publishable or reward-eligible.
Webhook event
Record subscriber ID, confirmed email hash, referrer, reader token and signup source in the referral ledger.
Proof needed: Buttondown webhook payload, timestamp, source path and consent state.
Webhook event
Increment referral counts only after the referred subscriber is confirmed.
Proof needed: Confirmed subscriber state and non-empty referrer metadata.
Webhook event
Mark the referral inactive for reward eligibility while preserving aggregate audit history.
Proof needed: Unsubscribe event timestamp and subscriber ID.
Append-only storage and derived totals for a testable referral audit trail before any live leaderboard claim.
Ledger store
Owner: local webhook handler
Record: One immutable line per Buttondown webhook event with event_id, event_type, received_at, subscriber_hash, referrer_token, reader_token, source_path and raw_payload_hash.
Reason: Keeps the audit trail append-only so referral counts can be rebuilt after fraud review or Buttondown export reconciliation.
Ledger store
Owner: derived build step
Record: Aggregate confirmed referral counts by reader_token plus held, inactive and disputed counts.
Reason: Lets the static leaderboard show aggregate proof without exposing emails or unapproved display names.
Ledger store
Owner: manual operator review
Record: Suspicious clusters, duplicate self-referrals, same-device patterns and sponsor reward eligibility holds.
Reason: Prevents prize or public-rank claims before moderation.
Minimum fields for the non-live Buttondown webhook handler and rebuild step.
Ledger field
Source: Buttondown webhook id or generated deterministic hash
Validation: Unique across the ledger; reject duplicate event ids.
Ledger field
Source: Buttondown webhook type
Validation: Allow subscriber.created, subscriber.confirmed and subscriber.unsubscribed only for first pass.
Ledger field
Source: Lowercase email hashed before local storage
Validation: Never store raw email in the referral ledger.
Ledger field
Source: Subscriber metadata referrer value
Validation: 3-80 letters, numbers, underscore or hyphen; empty means organic signup.
Ledger field
Source: Subscriber metadata reader_token value
Validation: Generated locally until Buttondown subscriber id is approved as canonical.
Ledger field
Source: Buttondown confirmed/unsubscribed status
Validation: Only confirmed records count toward public aggregate totals.
Webhook scenarios to verify before MY-2571 can move from static contract to live wiring.
Dry-run fixture
Event: subscriber.confirmed
Referrer: none
Expected: Create confirmed subscriber audit record; do not increment any referrer.
Dry-run fixture
Event: subscriber.confirmed
Referrer: cambridge-founder-001
Expected: Increment aggregate count after subscriber hash is unique and consent_state is confirmed.
Dry-run fixture
Event: subscriber.unsubscribed
Referrer: cambridge-founder-001
Expected: Mark referral inactive for reward eligibility while preserving historical aggregate audit.
Dry-run fixture
Event: subscriber.confirmed
Referrer: cambridge-founder-001
Expected: Hold in referral_review_queue.json when same subscriber_hash, same reader_token or same-device cluster appears.
Privacy and fraud controls before public rows or sponsor-backed rewards exist.
Use this as the MY-2571 live-wiring checklist after approval and test credentials.
What counts as proof for the referral/live leaderboard tracker.