← Back to experiment
BUILD & LAUNCH GUIDE

One small ask.
A clear setup.

Nearby discovery & sharing

Share is available in the sticky navigation, the mobile bottom bar, the landing prompt and the final results panel. Sharing links contain no participant details. Nearby public responses are visible on the landing and results pages before voting is required.

The hosting network’s approximate city estimate is used where available; visitors can correct it with Change city. It does not request GPS or save the inferred area to a participant response. A chosen browsing city is remembered for 30 days and does not alter a vote. Participants still choose whether to supply a city with their response, and can withdraw their public listing. Network-location availability and accuracy depend on the hosting request metadata; the manual fallback always remains available.

Current payment mode

Live PayPal checkout is enabled. Payments use real money and the live participant cohort.

What works now

Persistent anonymous voting; changes of mind update the same browser’s response; optional name, city, country and income; automatic city-based listings with upfront disclosure and withdrawal; aggregate results; nearby city distances; share links and downloadable aggregate PNG; protected administration. Actual results, nearby listings, income statistics, financial records and downloaded cards use stored responses and verified payments. The statistics page also offers a prominently labelled illustrative preview. No fictitious participant or payment records are added to the database.

PayPal sandbox checkout is implemented, including server-created US$1 orders, verified capture checks, signed webhook verification, duplicate-event handling and a refund ledger. The US sandbox seller, API credentials and payment webhook are now configured. A completed US$1 sandbox payment was verified on September 17, 2026. The app recorded one paid response, a US$0.52 provider-reported test fee and US$0.48 remaining, with no refund recorded at that check. Two actual PayPal webhook notifications passed verification and returned HTTP 200. Earlier direct API testing also confirmed that a repeated create request reused the same order. These are sandbox results, not live receipts or a guarantee of live pricing. Separate live PayPal configuration, merchant checks and live webhook verification are implemented. A real US$1 live payment was verified on September 17, 2026: one completed payment, a US$0.54 provider-reported fee, US$0.46 after that fee and no refund at verification. Two live webhook events passed verification without duplicating the paid response. This is an observed transaction, not a guaranteed fee for other payments or proof of bank settlement. Actual provider refund testing remains outstanding. Earlier Stripe test records remain intact.

Illustrative statistics

Before 100 verified live US$1 payments, the statistics page opens with an explicitly labelled fictitious example: 48% No, 28% Yes—payment not completed, 24% Yes—paid and US$240 in illustrative contributions. At US$1 per paid response, this represents 1,000 example responses: 480 No, 280 unpaid and 240 paid. The illustrative Yes-to-payment conversion is 46.2%.

A notice below the figures and a footnote explain that the example is intended to help the experiment get traction. Visitors can select View actual results at any time. The example is never added to the real totals, nearby listings, income statistics, administration or downloadable card. It does not unlock the income breakdown.

The server removes the preview at 100 verified live completed payments. Existing and new sandbox payments are identified separately and cannot advance that counter. Refunds or visibility withdrawal do not erase a historically completed payment. The server records live completion only after confirmation from the live provider. Test votes, listings, income and payment totals remain separate from the live cohort.

Screen flow

Question → optional details (or skip) → No: results / Yes: checkout → complete, cancel or Not now → results → optional sharing. A returning browser resumes its saved response. Saying yes after no updates that response. Payment remains exactly 100 US cents, with no quantity selector, tips, promotion codes, subscription or fee added.

PayPal checkout

The selected integration uses PayPal-hosted checkout with separate sandbox and live credentials. The app creates an order for exactly US$1.00, with no shipping, quantity choice, tips, subscription or added processing fee. Approval alone is not payment: the server captures an approved order and checks its amount, currency, recipient, participant reference and completed capture before counting it.

PayPal wallet is the initial checkout method. Guest card availability is controlled by PayPal and is not guaranteed. Separate Venmo, Apple Pay, Google Pay and Cash App Pay integrations are not enabled in this build. These methods must not be advertised as available until implemented and tested.

Public contact

Support, refund and privacy requests go to hello@wazwiq.com. This contact is published in the app footer, checkout, and Privacy & the experiment screen. Refund requests are reviewed by the organiser using the verified payment record. Public visibility can be withdrawn without changing financial records. Before expanding promotion, the organiser should finalize a retention schedule and review the buyer-facing PayPal account details.

Refund policy

Approved refunds will be reduced by any PayPal processing fees charged on the original contribution and not returned to us. We add no refund or handling fee. This does not limit any refund required by law, PayPal, or your card issuer.

We will confirm the actual fee deduction and refund amount before processing. This policy applies to contributions made after it is published; earlier contributions remain subject to the policy shown at payment.

Refund requests are reviewed through hello@wazwiq.com. The organiser checks the actual PayPal payment and retained fees, then issues the agreed refund against the original transaction in PayPal. Only a verified completed refund reduces the app’s financial totals. PayPal refund guidance.

Fees and eligibility

For a US account, standard domestic PayPal Checkout pricing is 3.49% + US$0.49, leaving approximately US$0.48 from US$1. Approved domestic Micropayments pricing is 4.99% + US$0.09, leaving approximately US$0.86. Micropayment pricing is not automatic and not every payment type qualifies. Ask PayPal to confirm the experiment, the exact US$1 checkout and the applicable rate. International payments, currency conversion, disputes and account-specific charges can change the remainder. Original processing fees generally remain payable after refunds.

Reviewed September 17, 2026. PayPal US fees · PayPal terms · Orders API · Webhook verification

Exact sandbox setup checklist

  1. Sign in to developer.paypal.com with the intended recipient’s account. In Testing Tools → Sandbox Accounts, create or use one US Business seller and a separate US Personal buyer. All funds in these accounts are fictitious.
  2. Under Apps & Credentials → Sandbox, create a REST app called “Cents Makes Sense” linked to that Business sandbox account. Copy its Client ID and Secret into the Site’s protected environment settings as PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET. Keep the secret out of chat and public code.
  3. Set PAYPAL_MERCHANT_ID to that sandbox seller’s Merchant ID / account ID. It must match the seller behind the REST app, not the buyer or a live account. The app verifies this recipient on every order.
  4. Under the same sandbox REST app, add the HTTPS webhook URL https://centsmakessense.org/api/paypal/webhook. Subscribe to CHECKOUT.ORDER.APPROVED, PAYMENT.CAPTURE.COMPLETED, PAYMENT.CAPTURE.PENDING, PAYMENT.CAPTURE.DENIED, PAYMENT.CAPTURE.REFUNDED, PAYMENT.REFUND.PENDING and PAYMENT.REFUND.FAILED. Store the resulting Webhook ID as PAYPAL_WEBHOOK_ID. This is an ID, not Stripe’s signing secret.
  5. Redeploy after saving environment settings. Checkout stays unavailable until all four values are present. With PAYPAL_MODE=sandbox, checkout calls api-m.sandbox.paypal.com. The sandbox webhook always accepts only sandbox certificate URLs, independent of the public mode.
  6. Vote Yes, skip optional details if desired, and continue with PayPal. Sign in using the separate sandbox Personal buyer. Confirm that the provider shows exactly US$1, then approve. Check one verified paid response and one US$1 capture. Open a return URL without paying and verify that it does not change the paid total.
  7. Use another test browser response to cancel checkout and another to test a decline/pending capture using PayPal sandbox testing tools. Neither may be counted as paid. Missing, declined or uncertain payments stay unpaid; uncertain or stale attempts may require organiser review before a new order.
  8. In PayPal’s Sandbox Webhooks Events, inspect actual event deliveries and resend the same completed event. Expect a 2xx response, one paid response and unchanged gross. Repeat with a partial refund and full refund. The built-in webhook simulator does not support PayPal’s postback signature-verification endpoint, so simulator events are not accepted as verified payments; use real sandbox transactions.
  9. Verify mobile checkout, an interrupted return, duplicate clicks, privacy withdrawal and the income threshold. Refunds reduce financial totals while historical paid participation remains recorded. No participant name, income or city is sent to PayPal by this app.
  10. ADMIN_EMAILS remains the protected organiser allowlist. Sign in with ChatGPT to access administration. Keep optional public details separate from PayPal records. The public support, refund and privacy contact is hello@wazwiq.com.

Live setup and controlled launch

  1. The organiser has confirmed that a private individual will receive and hold the funds, with final discretion over their use. The public disclosure does not name that individual. App promotion is the initial intention, but other uses are possible. Confirm that this disclosure remains accurate before accepting payments; the merchant account must still contain the recipient’s accurate identity.
  2. The organiser has confirmed the PayPal Business account upgrade. Before enabling real payments, check live-account eligibility, identity and bank verification, the accurately disclosed funding model and applicable fees. Configure live credentials, a live webhook and the correct live merchant recipient. The public support and privacy contact is hello@wazwiq.com. Confirm the statement descriptor and retention schedule, and follow the published refund policy.
  3. Run the provider tests above successfully. Decide the launch country scope and ad audience. Do not advertise the test preview as a live experiment.
  4. Set PAYPAL_LIVE_CLIENT_ID, PAYPAL_LIVE_CLIENT_SECRET, PAYPAL_LIVE_MERCHANT_ID and PAYPAL_LIVE_WEBHOOK_ID in protected settings. Register https://centsmakessense.org/api/paypal/live/webhook in the Live PayPal app for the same events listed above. After verification, set PAYPAL_MODE=live and redeploy. The live cohort starts without test votes, and uses a separate browser cookie.
  5. Public access and centsmakessense.org are already configured. After enabling live mode, have a separate real buyer pay exactly US$1. Confirm a single capture, verified webhook, paid response and actual fee, then verify refunds. An unapproved order does not prove payment or settlement.

Data integrity & privacy

A random HttpOnly SameSite browser cookie identifies a response; only its hash is stored. Payment records are separate from optional participant details. Server-side same-origin checks, prepared SQL, a honeypot and coarse IP/time-window rate limits reduce abuse. They do not guarantee one person per vote: clearing cookies, switching browsers or devices and shared browsers affect uniqueness. Further bot protection may be needed before a large advertising campaign.

Income is annual household income in USD, self-reported and optional. Only the distribution among verified paid participants is exposed, after at least 100 completed payments. Missing income is “Not provided.” Paid status measures historical completion, so later refunds do not erase completion; dollar totals subtract refunds. The income distribution uses this same historical paid cohort. Small bracket counts may still reveal information when combined with outside knowledge; group small cells if launching with a sensitive audience.

Providing a city automatically includes a participant in nearby results, as disclosed before submission. Missing names display as Anonymous. No city means no nearby listing. Income, cookie hashes and payment identifiers never appear in nearby lists or shared cards. Clearing the cookie loses the self-service control; contact hello@wazwiq.com for help with public visibility withdrawal requests. No card details are stored by this app.

Promotion concepts

01 / THE DIRECT ASK

Would you give $1?

A bold yellow screen with the question, then two equal choices. Copy: “Exactly US$1. No more, no less. Answer a small question about human nature. Taking part is free.”

02 / INTENT & ACTION

Saying yes is only half the story.

A split screen: “I would” / “I did.” Copy: “What happens between an answer and an action? Join a voluntary experiment. No payment required.”

03 / OPEN CURIOSITY

No right answer. Just yours.

A simple animated question mark resolves into $1. Copy: “With everything costing more, would you give $1 just because someone asked? See how people answer.”

Deployment and maintenance

The app runs as a Sites-hosted Cloudflare Worker with D1 persistence. Source, schema and migrations are versioned together. After source edits, generate migrations only for schema changes, run the build, save the source revision and publish the saved version. Environment changes require redeployment. Keep test and live datasets separate. Monitor failed webhooks and unknown fees; replay failed events. Expired rate-limit buckets should be purged on a retention schedule before a high-volume launch.

PAYPAL_MODE is controlled only through protected server settings. Adding credentials alone does not activate real checkout. Both webhook endpoints retain their own environment when public mode changes.