Monorepo for Aesthetic.Computer
aesthetic.computer
PayPal Integration Plan#
Overview#
Integrate PayPal as a payment option on the give page (give.aesthetic.computer) alongside existing USD (Stripe), DKK, and Crypto options.
Account Details#
- PayPal Account: mail@aesthetic.computer
- API Environment: Production (api-m.paypal.com)
Credentials Storage#
| Location | Purpose |
|---|---|
aesthetic-computer-vault/.env |
Local development, secure storage |
| MongoDB secrets collection | Netlify functions runtime access |
Environment Variables#
PAYPAL_CLIENT_ID=<stored in vault>
PAYPAL_CLIENT_SECRET=<stored in vault>
PAYPAL_API_URL=https://api-m.paypal.com
API Architecture#
PayPal Orders API v2#
- Auth: OAuth 2.0 (Client ID + Secret → Bearer Token)
- Create Order:
POST /v2/checkout/orders - Capture Payment:
POST /v2/checkout/orders/{id}/capture
Flow#
1. User selects amount on give page
2. Frontend calls /api/paypal (Netlify function)
3. paypal.mjs creates order via PayPal API
4. Returns approval URL
5. User redirected to PayPal to approve
6. PayPal redirects back to give.aesthetic.computer?paypal_success=1
7. Frontend calls /api/paypal/capture with order ID
8. paypal.mjs captures payment
Implementation Checklist#
✅ Completed#
- PayPal tab in currency selector
- PayPal section UI (header, button, email)
- PayPal.me direct link button
- Copyable email address
- Multi-language support (EN, DA, DE, ES, ZH)
- PayPal QR code integration
- CSS styling (blue theme #0070ba)
- Give button "PP" cycling
- Credentials stored in vault
🔄 In Progress#
- paypal.mjs Netlify endpoint
- MongoDB secrets sync
❌ Not Started#
- Custom amount input (like Stripe)
- Payment capture flow
- Success/failure handling on redirect
- Transaction logging
Netlify Function: paypal.mjs#
Endpoints#
// Create order
POST /api/paypal
Body: { amount: "10.00", currency: "USD" }
Returns: { id: "ORDER_ID", approval_url: "https://paypal.com/..." }
// Capture payment (optional, if using redirect flow)
POST /api/paypal/capture
Body: { order_id: "ORDER_ID" }
Returns: { status: "COMPLETED", ... }
Implementation Pattern#
// Follow give.js pattern
import { MongoClient } from "mongodb";
const getSecrets = async () => {
const client = await MongoClient.connect(process.env.MONGODB_URI);
const db = client.db("aesthetic");
return db.collection("secrets").findOne({ name: "paypal" });
};
const getAccessToken = async (clientId, clientSecret) => {
const response = await fetch("https://api-m.paypal.com/v1/oauth2/token", {
method: "POST",
headers: {
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
});
const data = await response.json();
return data.access_token;
};
const createOrder = async (accessToken, amount, currency = "USD") => {
const response = await fetch("https://api-m.paypal.com/v2/checkout/orders", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
intent: "CAPTURE",
purchase_units: [{
amount: {
currency_code: currency,
value: amount,
},
description: "Aesthetic Computer Contribution",
}],
application_context: {
return_url: "https://give.aesthetic.computer?paypal_success=1",
cancel_url: "https://give.aesthetic.computer?paypal_cancel=1",
brand_name: "Aesthetic Computer",
user_action: "PAY_NOW",
},
}),
});
return response.json();
};
Limitations#
- No Monthly Subscriptions: Orders API is one-time only
- Would need PayPal Subscriptions API for recurring
- User acknowledged this is acceptable
- Currency Support: USD, EUR, GBP, etc. (no DKK via PayPal API)
QR Code#
- Asset URL:
https://assets.aesthetic.computer/images/paypal-qrcode.png - Links to: PayPal.me/aestheticcomputer
- Purpose: Quick mobile scanning for donations
Security Notes#
- Never commit credentials to main repo
- Use vault for local dev
- Use MongoDB secrets for production
- Rotate credentials periodically
- Monitor for unauthorized transactions
Testing#
- Use PayPal Sandbox for development testing
- Create sandbox accounts at developer.paypal.com
- Test with small amounts ($0.01) in production
Related Files#
system/public/give.aesthetic.computer/index.html- Give page UIsystem/netlify/functions/give.js- Stripe endpoint (reference)system/netlify/functions/paypal.mjs- PayPal endpoint (to create)aesthetic-computer-vault/.env- Credentials storage