PRO

Your plan

Checking…

Your tokens

Checking…

$ USD

Plans

Paid out of the balance above. Nothing here asks for a card — add tokens first, then buy the plan with them.

Payment methods

Set up in .env at the project root — never in this app and never in the repository. .env.example names every variable. Restart the server after editing it: the environment is read once, when the process starts.

Setting them up

The money lands wherever these keys belong and nowhere else — no email address anywhere in this app sends it anywhere. Both provider accounts must be the ones under the operator's own address.

PayPal
  1. A PayPal Business account. A personal one cannot take card payments through the Orders API.
  2. developer.paypal.com → Apps & Credentials → Sandbox → Create App. Copy the Client ID and Secret.
  3. Put them in .env as PAYPAL_CLIENT_ID and PAYPAL_SECRET, leave PAYPAL_ENV=sandbox, restart, and press Test the connections above.
  4. Buy the monthly plan with a sandbox buyer account. The whole path — order, approve, return, capture, plan — has to work once.
  5. Only then: switch to the Live tab in the same dashboard, take the live Client ID and Secret, and set PAYPAL_ENV=live.

Nothing but the exact string live switches environment, so a half-finished edit stays in the sandbox rather than taking real money.

Binance Pay
  1. A Binance account with completed KYC, then apply for a merchant account — this needs business verification and is the slow step.
  2. Merchant dashboard → API keys. Copy the API key and the secret.
  3. BINANCE_PAY_KEY and BINANCE_PAY_SECRET in .env, restart, and press Test the connections.
  4. If the dashboard asks for allowed domains or a webhook URL, this app is served on 127.0.0.1 — there is no public address to give it yet, and no webhook is used. See below.

Settles in USDT, priced at parity with the dollar price. The signature is the whole integration and a wrong one is refused with a message that names nothing — which is what the test button is for.

What is still missing, and why

Webhooks. The normal backstop for "the customer paid and closed the tab" is a webhook from the provider. A webhook needs a public URL, and this app is served on 127.0.0.1 — a provider cannot reach it, so a webhook route here would be dead code that looks like a safety net.

What stands in for it: this page asks about every unfinished order each time it loads, so a customer who closed the tab gets their plan the next time they open it. When there is a real hostname, add the webhook — and register it before the sign-in gate in web/serve.js, because a payment provider cannot sign in.

No live call has ever been made from this project. The requests are built to both providers' documentation and the whole purchase is tested against a scripted provider (node CRBuilderApp/test-billing.js), which proves this app does the right thing with the answers it is given — not that these are the answers it will get. The first sandbox purchase is the test that matters.

Orders

Every checkout this app has opened. A claimed row is somebody saying they have transferred pesos — open Mercado Pago, find the reference in the transfer note, and grant it here. That is the only way a peso transfer becomes a plan.

Loading…