chrome-extension-payments
Skill2 starsChanged 52 days agoMITView on GitHub
Add real payments to a Chrome MV3 extension — monthly/yearly subscriptions, a lifetime one-time purchase, PayPal (Subscriptions + Orders API) and USDT/BEP20 crypto payments, server-derived entitlements, plan changes, discount codes, an affiliate program, and an admin dashboard. Trigger for "add payments to chrome extension", "subscription extension", "paypal subscription", "accept USDT", "crypto payments", "lifetime license", "paywall", "pro plan", "monetize my extension". Ported from a shipped MV3 + Hono/Postgres backend: verified webhooks, idempotent settlement, exact-amount crypto invoices, reconciliation jobs — not a theoretical sketch.
- Reads credentials
In this repository4 other files it gives its agents.
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 76
Wire PayPal: create the product + plans once with a setup script, implement createCheckout / createOrder / captureOrder / verifyWebhook / …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Chrome Extension Payments
Monetize a Chrome MV3 extension with a real backend: subscriptions, a lifetime purchase, two payment rails (PayPal + USDT/BEP20), server-derived entitlements, and the admin/affiliate/discount machinery around them. Every pattern here shipped in production; alternatives are noted, not built out.
Scope — read this first
This skill does not cover:
- Login / accounts — sessions, Google SSO, email/password. Use
chrome-extension-authfirst; this skill assumesrequireAuthmiddleware and auserstable already exist. - Chrome Web Store listing, permission justifications, screenshots — use
chrome-web-store-listing. - Deploying the backend, TLS, CI/CD — use
chrome-extension-deploy. - MV3 basics (WXT, messaging, storage/sync, build tooling) — use
chrome-extension-dev.
Assumed stack: Hono (Node) API, raw pg (no ORM), Postgres, a WXT/React extension with a background
script that is the only holder of the session token. Swap the framework; keep the shape.
1. Choose your payment providers
| Provider | Fee | Merchant of record (tax) | Chargebacks | Works where Stripe doesn't | Setup cost |
| PayPal (Subscriptions + Orders API) | ~4.4% + $0.30 | No — you owe your own sales tax/VAT | Yes, PayPal-mediated | Yes | Low — product/plan API + one webhook |
| USDT (BEP20) | Network gas only (~$0.10–0.30), no processor fee | No — you are the merchant | No — on-chain is final | Yes, anywhere crypto is legal | Medium — RPC reads, address-activity webhook |
| Stripe | ~2.9% + $0.30 | No | Yes | No — blocked/unavailable in many countries, and Chrome Web Store extension billing has its own restrictions | Low, best DX |
| Paddle / Lemon Squeezy | ~5% flat | Yes — they collect and remit tax as merchant of record | Handled by them | Yes | Low, but you give up direct control of checkout UI and payout timing |
Decision: this skill implements PayPal + USDT — the proven path when Stripe is unavailable or undesirable and you want to keep 100% of a crypto sale with no chargeback risk. If you have US/EU customers and want tax handled for you, evaluate Paddle or Lemon Squeezy instead (their hosted-checkout docs cover that path; do not hand-roll it here). If Stripe is available in your market and you don't need a crypto rail, Stripe's Billing + Checkout Session APIs are simpler than PayPal's — this skill does not template it, but the entitlement/webhook-idempotency patterns below transfer directly.
2. Entitlement model
- Tiers are
free | pro(or your tier set). One column,users.tier, is the fast-read projection — never the source of truth. - Source of truth is derived server-side from three places, in this priority:
users.lifetime_at(set, never unset except on refund) ORusers.comp_access(admin-granted) OR the newest row insubscriptionswithstatus = 'active'ANDcurrent_period_end > now(). - Never trust the client for entitlement.
GET /v1/mereturns{ tier, lifetime, subscription }; the extension caches this response and gates features off the cache, but every privileged API call re-checks the database, not the cached flag. - The extension caches
/meinstorage.local, refreshes it on a dailyalarmstick (re-armed ononStartup— Chrome can drop alarms across a browser restart), and immediately after any checkout, claim, or cancel action resolves. - Client-side "is this still Pro" also compares the cached
current_period_endagainstDate.now()so a lapsed plan doesn't read as Pro for up to a day between refreshes. - Graceful downgrade: losing Pro never deletes data. Existing saved items stay readable and editable; only the "create new" action is gated behind the entitlement check.
Full code (types, isProFromMe, useEntitlement, alarm wiring, message-passing contract) in
references/entitlements-and-checkout.md.
3. Data model
Postgres, raw SQL, no ORM. Every CREATE TABLE/ALTER TABLE is IF NOT EXISTS so the same script
runs safely on every boot — this is your only migration system. Money as NUMERIC(10,2) (USD) or
NUMERIC(20,8) (USDT); every purchase row carries created_at, and cancellable rows carry
cancelled_at + cancelled_by. See references/data-model.md and assets/schema-template.sql.
4. Numbered workflow
- Define the catalog — plan codes, prices, tiers, one lifetime item — in one server-side module
(
plans.ts). The client never sends a price; it sends a plan code. - Apply the schema (
assets/schema-template.sql) — users, subscriptions, webhook_events, one_time_purchases, crypto_invoices, crypto_transfers, discount_codes, affiliate tables. - Wire PayPal: create the product + plans once with a setup script, implement
createCheckout/createOrder/captureOrder/verifyWebhook/parseWebhook, mount the webhook route. Seereferences/paypal.md. - Wire USDT/BEP20: exact-amount invoices, a minimal JSON-RPC reader with failover, the
Alchemy address-activity webhook, and the manual tx-hash claim fallback. See
references/usdt-bep20.md. - Build the in-popup checkout UX: plan picker → PayPal approval opens a new tab (never an embedded
SDK) → static return/cancel pages served by the API → popup polls invoice/subscription status. See
references/entitlements-and-checkout.md. - Apply billing events idempotently: claim the webhook event id before processing, release the claim on failure so the provider's retry gets a real attempt, mark it processed only after every side effect (tier write, discount redemption, commission) has committed.
- Add plan changes: upgrade-only in an MVP (bigger interval/tier), prorate on PayPal, no proration
on the crypto rail (a new full-price pass stacks onto the end of the current one). See
references/plan-changes-discounts-affiliate.md. - Add discount codes and affiliate: first-charge-only discounts with redemption limits; referral
codes discount the referee and pay the referrer a commission held for N days before payout. Rates
live in a
app_settingsDB row, editable at runtime, not in env vars. - Build the admin API: overview/revenue/users/orders/withdrawals endpoints behind a single shared secret compared in constant time. Never behind the same auth as customers.
- Run maintenance jobs: a scheduler tick that matures commissions, expires lapsed subscriptions
(with a grace check so cancellation never revokes an already-paid period), sweeps confirmed crypto
invoices, expires stale ones, and reconciles any invoice that reached
paidbut never got its entitlement applied (crash recovery). - Test before going live: a
paypal:checkstyle script that verifies credentials, webhook subscriptions, and plan pricing without charging anything; acrypto:simulatescript against a faked chain and a scratch database; manual webhook replay. Seereferences/testing-and-operations.md.
5. Plan-change quick table
| From → To | Same provider | Cross-provider |
| Month → Year (PayPal) | Prorated new subscription, charged the difference now | n/a |
| Month → Year (crypto) | New full-price pass stacks onto the end of the current one — no proration | n/a |
| Year → Month | Not supported in an MVP — no clean way to apply it without re-billing or a manual revise call; let it run out | Same |
| Any plan → Lifetime | Always allowed. Buying Lifetime auto-cancels every live subscription so the customer is never billed again for something Lifetime already covers | Same |
| Lifetime → anything | Blocked — no further purchase is offered once Lifetime is granted | — |
6. Security checklist
- Verify every webhook signature before parsing the body as trusted: PayPal via
/v1/notifications/verify-webhook-signature, Alchemy (or your chain provider) via HMAC-SHA256 over the raw body withtimingSafeEqual. An unverified webhook is a free-tier endpoint. - Never trust a client-supplied amount or price. The client sends a plan code; the server looks up the price. A discount is priced server-side from the code, not from a client-sent percentage.
- Idempotency everywhere money moves: webhook event id claimed via
INSERT ... ON CONFLICT, capture/settle writes guarded by a conditionalUPDATE ... WHERE status <> 'paid', and any insert that could double-credit backed by a real unique constraint (not just an application check). - Secrets stay server-side only — API keys, webhook signing keys, the admin secret. Nothing payment-related belongs in the extension bundle; it is publicly downloadable.
- Compare secrets in constant time (
crypto.timingSafeEqualover a hash, not===) for the admin secret and any webhook HMAC check. - Grant access only after money actually moved. PayPal order approval is not payment —
capture it and check the capture's own status is
COMPLETEDbefore granting anything. - Rate-limit checkout, discount lookup, and crypto claim endpoints — a discount/claim endpoint is a guessing oracle otherwise.
- Log every refund/chargeback and act on repetition — disable the account outright on a chargeback; flag after N ordinary refunds.
- Refuse to boot in production with placeholder secrets (default session secret, missing admin
secret, missing allowed-origins list,
.env.examplevalues still in place).
7. References
references/entitlements-and-checkout.md— tier model, caching, alarms, feature gating, popup checkout flow, message-passing contract.references/paypal.md— catalog setup script, Subscriptions + Orders API, webhook verification and idempotent event handling, reconciliation, sandbox vs live.references/usdt-bep20.md— exact-amount invoices, RPC reader with failover, Alchemy webhook, manual claim, confirmations/expiry, stacking, crypto discount, simulation.references/plan-changes-discounts-affiliate.md— upgrade/downgrade rules, discount code validation, affiliate rates/attribution/payouts, admin auth.references/data-model.md— schema walkthrough, money representation, audit fields, key relationships.references/testing-and-operations.md— verification scripts, webhook replay, maintenance jobs, production checklist.assets/schema-template.sql— generic, trimmed, idempotent Postgres schema to start from.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

