// One-time PayPal setup: creates the product + the recurring billing plans and // prints the plan IDs to paste into your environment. // // 1. Set PAYPAL_CLIENT_ID / PAYPAL_SECRET (and PAYPAL_ENVIRONMENT) in .env.local // 2. node scripts/paypal-setup-plans.mjs // 3. Copy the printed PAYPAL_*_PLAN_ID lines into .env.local / production env // // Amounts mirror the app's pricing (Pro $29/mo, Landlord $59/mo); yearly is // billed at 10× monthly (~2 months free). Adjust in the PayPal dashboard if you // want different annual pricing. Safe to re-run (it creates fresh plans). import { config } from "dotenv" config({ path: ".env.local", quiet: true }) const ENV = process.env.PAYPAL_ENVIRONMENT === "live" ? "live" : "sandbox" const BASE = ENV === "live" ? "https://api-m.paypal.com" : "https://api-m.sandbox.paypal.com" const id = process.env.PAYPAL_CLIENT_ID const secret = process.env.PAYPAL_SECRET if (!id || !secret) { console.error("[paypal-setup] Set PAYPAL_CLIENT_ID and PAYPAL_SECRET in .env.local first.") process.exit(1) } async function getToken() { const r = await fetch(`${BASE}/v1/oauth2/token`, { method: "POST", headers: { Authorization: `Basic ${Buffer.from(`${id}:${secret}`).toString("base64")}`, "Content-Type": "application/x-www-form-urlencoded", }, body: "grant_type=client_credentials", }) if (!r.ok) throw new Error(`auth ${r.status}: ${await r.text()}`) return (await r.json()).access_token } const token = await getToken() const post = (path, body) => fetch(`${BASE}${path}`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", Prefer: "return=representation", }, body: JSON.stringify(body), }) console.log(`[paypal-setup] Environment: ${ENV}`) const prodRes = await post("/v1/catalogs/products", { name: "Property Management Network", description: "Property Management Network subscription", type: "SERVICE", category: "SOFTWARE", }) if (!prodRes.ok) { console.error("[paypal-setup] product creation failed:", await prodRes.text()) process.exit(1) } const product = await prodRes.json() console.log(`[paypal-setup] Product: ${product.id}`) const AMOUNTS = { pro: 29, landlord: 59 } const envLines = [] for (const plan of ["pro", "landlord"]) { for (const interval of ["month", "year"]) { const amount = interval === "month" ? AMOUNTS[plan] : AMOUNTS[plan] * 10 const res = await post("/v1/billing/plans", { product_id: product.id, name: `${plan[0].toUpperCase()}${plan.slice(1)} ${interval === "month" ? "Monthly" : "Yearly"}`, status: "ACTIVE", billing_cycles: [ { frequency: { interval_unit: interval === "month" ? "MONTH" : "YEAR", interval_count: 1 }, tenure_type: "REGULAR", sequence: 1, total_cycles: 0, pricing_scheme: { fixed_price: { value: amount.toFixed(2), currency_code: "USD" } }, }, ], payment_preferences: { auto_bill_outstanding: true, setup_fee_failure_action: "CONTINUE", payment_failure_threshold: 2, }, }) if (!res.ok) { console.error(`[paypal-setup] plan ${plan}/${interval} failed:`, await res.text()) continue } const p = await res.json() const key = `PAYPAL_${plan.toUpperCase()}_${interval === "month" ? "MONTHLY" : "YEARLY"}_PLAN_ID` console.log(` ${plan}/${interval} $${amount} → ${p.id}`) envLines.push(`${key}=${p.id}`) } } console.log("\n[paypal-setup] Add these to your environment:\n") console.log(envLines.join("\n"))