Buttondown referral wiring

Referral attribution contract before live leaderboard work.

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.

Metadata contract

Fields to preserve when replacing the static form with the approved Buttondown embed or API route.

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.

Metadata field

reader_token

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

signup_source

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

utm_campaign

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.

Webhook events

Events needed before referral counts become publishable or reward-eligible.

Webhook event

subscriber.created

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

subscriber.confirmed

Increment referral counts only after the referred subscriber is confirmed.

Proof needed: Confirmed subscriber state and non-empty referrer metadata.

Webhook event

subscriber.unsubscribed

Mark the referral inactive for reward eligibility while preserving aggregate audit history.

Proof needed: Unsubscribe event timestamp and subscriber ID.

Local ledger plan

Append-only storage and derived totals for a testable referral audit trail before any live leaderboard claim.

Ledger store

referral_events.jsonl

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

referral_totals.json

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

referral_review_queue.json

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.

Ledger schema

Minimum fields for the non-live Buttondown webhook handler and rebuild step.

Ledger field

event_id

Source: Buttondown webhook id or generated deterministic hash

Validation: Unique across the ledger; reject duplicate event ids.

Ledger field

event_type

Source: Buttondown webhook type

Validation: Allow subscriber.created, subscriber.confirmed and subscriber.unsubscribed only for first pass.

Ledger field

subscriber_hash

Source: Lowercase email hashed before local storage

Validation: Never store raw email in the referral ledger.

Ledger field

referrer_token

Source: Subscriber metadata referrer value

Validation: 3-80 letters, numbers, underscore or hyphen; empty means organic signup.

Ledger field

reader_token

Source: Subscriber metadata reader_token value

Validation: Generated locally until Buttondown subscriber id is approved as canonical.

Ledger field

consent_state

Source: Buttondown confirmed/unsubscribed status

Validation: Only confirmed records count toward public aggregate totals.

Dry-run fixtures

Webhook scenarios to verify before MY-2571 can move from static contract to live wiring.

Dry-run fixture

Organic subscriber

Event: subscriber.confirmed

Referrer: none

Expected: Create confirmed subscriber audit record; do not increment any referrer.

Dry-run fixture

Clean referral

Event: subscriber.confirmed

Referrer: cambridge-founder-001

Expected: Increment aggregate count after subscriber hash is unique and consent_state is confirmed.

Dry-run fixture

Unsubscribe after referral

Event: subscriber.unsubscribed

Referrer: cambridge-founder-001

Expected: Mark referral inactive for reward eligibility while preserving historical aggregate audit.

Dry-run fixture

Duplicate or suspicious referral

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.

Leaderboard rules

Privacy and fraud controls before public rows or sponsor-backed rewards exist.

OpenLeaderboard rulePublish display names only after explicit opt-in; never publish email addresses.OpenLeaderboard ruleCount confirmed subscribers only.OpenLeaderboard ruleHold same-device, same-IP or suspicious clusters for manual review before reward eligibility.OpenLeaderboard ruleKeep prize draws inactive until sponsor terms, eligibility and fulfilment owner are approved.OpenLeaderboard ruleShow aggregate founding-reader counts before personal leaderboard rows are approved.OpenRelease gateRender aggregate founding-reader count from referral_totals.json before any named rows.OpenRelease gatePublish named leaderboard rows only after explicit opt-in and editorial approval.OpenRelease gateKeep prize draw copy hidden until sponsor terms, eligibility, fulfilment owner and fraud checks are approved.OpenRelease gateAttach webhook fixture output, ledger rebuild output and static /buttondown-referrals/ screenshot to MY-2571 before closing.

Implementation steps

Use this as the MY-2571 live-wiring checklist after approval and test credentials.

OpenWiring stepAdd Buttondown subscriber metadata fields for referrer, reader_token, signup_source and utm_campaign.OpenWiring stepReplace the static subscribe form with the approved Buttondown embed or API-backed form while preserving hidden referral fields.OpenWiring stepCreate a local referral ledger table or JSONL audit file fed by Buttondown webhooks.OpenWiring stepBackfill existing confirmed subscribers only if Buttondown export includes consent-safe referral metadata.OpenWiring stepUpdate /leaderboard/ from placeholder to aggregate counts after webhook verification passes.OpenWiring stepConfirm internally for approval before publishing named leaderboard rows, prize mechanics or reward sponsor copy.

Linear proof

What counts as proof for the referral/live leaderboard tracker.

OpenLinear proofReference MY-2571 for Buttondown referral and live leaderboard wiring.OpenLinear proofAttach the generated /buttondown-referrals/ page and this JSON contract as static proof.OpenLinear proofDo not close MY-2571 until Buttondown webhook handling, ledger persistence and leaderboard rendering are verified against a non-live test subscriber.OpenLedger proofMY-2571 can use this file as the ledger schema proof for the non-live wiring step.OpenLedger proofMY-2577 can reference it as Cambridge portfolio progress without claiming live referral tracking.OpenLedger proofDo not mark referral wiring complete until a non-live Buttondown test subscriber exercises the full create-confirm-unsubscribe path.