Skip to content
Back to skills

Chrome Extension Payments

ASecurity

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 shipp...

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 24, 2026
businessrustgosqlreactnoderailstestingapidatabasebackend

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned September 24, 2026

npx -y skills add thomaslimited/chrome-extension-skills --skill chrome-extension-payments --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Chrome Extension Payments?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Chrome Extension Payments
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thomaslimited-chrome-extension-payments/badge)](https://www.skillsdirectory.com/skills/thomaslimited-chrome-extension-payments)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: chrome-extension-payments
description: 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.
license: MIT
---

# 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-auth` first; this
  skill assumes `requireAuth` middleware and a `users` table 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) OR `users.comp_access` (admin-granted) OR the newest row in
  `subscriptions` with `status = 'active'` AND `current_period_end > now()`.
- **Never trust the client for entitlement.** `GET /v1/me` returns `{ 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 `/me` in `storage.local`, refreshes it on a daily `alarms` tick (re-armed on
  `onStartup` — 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_end` against `Date.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

1. **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*.
2. **Apply the schema** (`assets/schema-template.sql`) — users, subscriptions, webhook_events,
   one_time_purchases, crypto_invoices, crypto_transfers, discount_codes, affiliate tables.
3. **Wire PayPal**: create the product + plans once with a setup script, implement
   `createCheckout` / `createOrder` / `captureOrder` / `verifyWebhook` / `parseWebhook`, mount the
   webhook route. See `references/paypal.md`.
4. **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`.
5. **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`.
6. **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.
7. **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`.
8. **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_settings` DB row, editable at runtime, not in env vars.
9. **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.
10. **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 `paid` but never got its
    entitlement applied (crash recovery).
11. **Test before going live**: a `paypal:check` style script that verifies credentials, webhook
    subscriptions, and plan pricing without charging anything; a `crypto:simulate` script against a
    faked chain and a scratch database; manual webhook replay. See `references/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 with `timingSafeEqual`. 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 conditional `UPDATE ... 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.timingSafeEqual` over 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 `COMPLETED` before 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.example` values 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.

Files in this skill

  • SKILL.md11.1 KB
  • assets/schema-template.sql12 KB
  • references/data-model.md6.2 KB
  • references/entitlements-and-checkout.md8.3 KB
  • references/paypal.md10.9 KB
  • references/plan-changes-discounts-affiliate.md9.5 KB
  • references/testing-and-operations.md8.5 KB
  • references/usdt-bep20.md11.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.