Repository navigation
Pricing page + working Pro/Lifetime checkout via CoinPay (all coins, PayPal, card) - #642
Merged
Merged
Conversation
…CoinPay (all coins + PayPal/card)
ugig had 1,167 signups in 30 days and zero Pro purchases: "Upgrade to Pro"
linked to /signup, /pricing was a 404, and the only checkout hardcoded
usdc_pol.
- /pricing: server-rendered, indexable (canonical, robots index, JSON-LD
offers), plans and prices from src/lib/plans.ts; in sitemap and footer.
- /checkout?plan=monthly|annual|lifetime: signed-out buyers go to
/login?redirect=... and come back (LoginForm and Sign in with CoinPay now
honor a same-site redirect). Coin picker lists every coin ugig's CoinPay
business accepts, live from /supported-coins (16 today), plus PayPal or
card (PayPal guest checkout through CoinPay; never Stripe).
- POST /api/payments/coinpayportal/create: any live CoinPay coin, or
method=paypal; prefers CoinPay hosted checkout sessions
(POST /api/checkout/sessions) when CoinPay serves them, feature-detected
with a 5 min negative cache. Every payment carries metadata
{property: ugig.net, user_id, username, email, ugig_payment_id, type,
plan, rail}; PayPal and sessions also get customer_email. Crypto passes
idempotency_key and falls back to coinpayportal.com/pay/<id>. A coin
CoinPay refuses at create (USDC on Base today) is hidden for an hour.
- Webhook settlement finds the row by coinpay_payment_id, then by
metadata.ugig_payment_id (hosted sessions; owner checked), then rebuilds
it from signed metadata when the plan price is covered.
- GET /api/payments/coinpayportal/options for API/CLI parity; openapi.json.
- addMonths clamps to month end (Oct 31 + 1 month = Nov 30, not Dec 1).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| return; | ||
| } | ||
| if (data.checkout_url) { | ||
| window.location.href = data.checkout_url as string; |
| // Checkout through CoinPay: any coin it supports, PayPal or card. The | ||
| // /checkout page picks the rail; this page only chooses the plan. | ||
| const handleCryptoCheckout = (plan: CoinPayPlan) => { | ||
| window.location.href = checkoutHref(plan); |
| <Header /> | ||
| <script | ||
| type="application/ld+json" | ||
| dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd()) }} |
ThreatCrush Security Scan57 finding(s) HIGH/CRITICAL: 1 | MEDIUM: 12 | LOW: 44
…and 7 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Revenue audit 2026-10-21: 1,167 signups in 30 days, zero Pro subscriptions ever. "Upgrade to Pro" linked to /signup, /pricing returned 404, and the only checkout (dashboard/subscription) hardcoded USDC on Polygon.
What
index, follow, JSON-LD offers), Free / Pro ($9/mo, $90/yr) / Lifetime ($100) fromsrc/lib/plans.ts. Added to sitemap and footer./login?redirect=/checkout?plan=...and land back on checkout after signing in (LoginForm and Sign in with CoinPay now honor a same-siteredirect)./api/supported-coins(16 today: USDC/USDT on several chains, BTC, BCH, ETH, POL, SOL, DOGE, XRP, ADA, BNB). Plus PayPal or card (PayPal guest checkout on CoinPay's hosted page). No Stripe.POST /api/payments/coinpayportal/create: any live coin ormethod: "paypal". Prefers CoinPay hosted checkout sessions (POST /api/checkout/sessions) when CoinPay serves them (feature-detected: 404/405/501 means fall back, cached 5 min).{property: "ugig.net", user_id, username, email, ugig_payment_id, type, plan, rail}; PayPal and sessions also sendcustomer_email. Crypto sendsidempotency_key.coinpay_payment_id, thenmetadata.ugig_payment_id(hosted sessions; owner checked), then rebuilds the row from the signed metadata if the local insert was lost (only when the plan price is covered).GET /api/payments/coinpayportal/optionsfor API/CLI parity; openapi.json updated./checkout.addMonthsclamps to month end (paying on Oct 31 gave Pro through Dec 1; also a date-dependent test failure today).Tested
vitest run: 307 files / 3007 tests pass;tsc --noEmitclean; eslint clean on touched files;bun run buildOK./login?redirect=%2Fcheckout%3Fplan%3Dannual; signed in, all 16 coins in the picker; created a real unpaid USDC (Polygon) $9 payment (CoinPay hosted page 200) and a real unpaid PayPal $100 Lifetime payment (coinpayportal.com/pay/paypal/... 200) as the riotcoder account.🤖 Generated with Claude Code