# infraforlightning.md

Lightning infrastructure for highermark — how payments, the $85.21 Lightning checkout, and the scrolling support QR codes actually work, and how to wire the demo to real money.

---

## 0. Overview

highermark offers two checkout paths:

| Path | Price | Rail | Ship time |
|---|---|---|---|
| Card | $110 | Stripe (`buy.stripe.com/...`) | standard |
| Lightning | **$85.21** | Arkade (`arkade.money`) + your node | ~1 week faster |

Lightning is cheaper (no card fees, no chargeback risk) and lets us prioritize the order, so we pass the savings and the faster ship time to you. The modal nudges card-payers toward Lightning twice before sending them to Stripe — keep that flow; it materially shifts volume to the cheaper rail.

The left column of the Lightning view shows **support QR codes** ($0.01 → $5,000) and a **BTCPayServer shout box**. Those are the pieces this doc scaffolds.

---

## 1. Components you need

- **A Lightning node** — LND, Core Lightning (CLN), or a managed option (Voltage, Greenlight). On Umbrel/Start9 this is one click.
- **An LNURL / Lightning Address server** — so `pay@highermark.xyz` resolves. Options: LNbits (LNURLp extension), `lightning-address`/`lnurl-pay` server, or BTCPay's LNURL support.
- **An invoicing API** — LNbits API or BTCPay Greenfield API to mint invoices on demand.
- **Arkade** — used as the consumer-facing Lightning checkout (`arkade.money`). The `arkadeBtn` in `pay.js` opens it; replace with your Arkade order link / deep link.

---

## 2. Lightning Address (`pay@highermark.xyz`)

Serve this JSON at `https://highermark.xyz/.well-known/lnurlp/pay`:

```json
{
  "callback": "https://highermark.xyz/lnurlp/pay/callback",
  "minSendable": 1000,
  "maxSendable": 500000000000,
  "metadata": "[[\"text/plain\",\"highermark support\"]]",
  "tag": "payRequest",
  "commentAllowed": 210
}
```

The `commentAllowed` field is what powers the **shout box** (see `btcpayserver.md`) — payers attach a message with their sats.

---

## 3. Generating the scrolling support QR codes  ← scaffolding

The QR rail currently uses **pre-generated SVGs** in `assets/qr/` (amounts: $0.01, $1, $10, $100, $230, $850, $2,000, $3,500, $5,000). Each encodes a placeholder:

```
lightning:pay@highermark.xyz?amount=<amt>&label=highermark-founder
```

### 3a. Regenerate the static SVGs (offline, what we shipped)

```bash
pip install qrcode
python3 - <<'PY'
import qrcode, qrcode.image.svg as svg
amounts = ["0.01","1","10","100","230","850","2000","3500","5000"]
for a in amounts:
    data = f"lightning:pay@highermark.xyz?amount={a}&label=highermark-founder"
    qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M, box_size=10, border=2)
    qr.add_data(data); qr.make(fit=True)
    img = qr.make_image(image_factory=svg.SvgPathImage)
    fn = f"assets/qr/qr_{a.replace('.','_')}.svg"; img.save(fn)
    s = open(fn).read().replace('fill:#000000','fill:#19f0ff').replace('fill="#000000"','fill="#19f0ff"')
    open(fn,'w').write(s)
PY
```

### 3b. Generate REAL invoices client-side (production)

Static QR codes are fine for tip jars and fixed prices. For unique, expiring invoices, mint one per scan from your node and render it live:

```js
// 1) ask your backend to create an invoice from LNbits/BTCPay
async function newInvoice(usd) {
  const r = await fetch('/api/ln/invoice', {
    method: 'POST', headers: {'Content-Type':'application/json'},
    body: JSON.stringify({ usd })           // backend converts USD→sats at current rate
  });
  return (await r.json()).bolt11;            // "lnbc..."
}

// 2) render it as a QR (qrcode-generator, ~5KB)
import QR from 'qrcode-generator';
function renderInvoice(bolt11, el) {
  const qr = QR(0, 'M'); qr.addData('lightning:' + bolt11.toUpperCase()); qr.make();
  el.innerHTML = qr.createSvgTag({ cellSize: 4, margin: 2 });
}
```

LNbits invoice (backend):
```bash
curl -X POST https://YOUR_LNBITS/api/v1/payments \
  -H "X-Api-Key: $LNBITS_INVOICE_KEY" -H "Content-type: application/json" \
  -d '{"out": false, "amount": 1600, "memo": "highermark $1", "unit": "sat"}'
# → { "payment_hash": "...", "payment_request": "lnbc..." }
```

### 3c. USD→sats conversion

Don't hard-code a BTC price. Pull a rate at invoice time (your node/LNbits does this when `unit:"USD"` where supported, or fetch from a price API) and label the QR with the USD figure while the invoice carries the sat amount. The shipped SVGs intentionally show only the USD label for that reason.

### 3d. Hook into the front-end

`assets/js/pay.js` controls the rail: `startQR()` runs the VHS-glitch interval and the SunbirdComputers popout. To go live, replace the static `<img src="assets/qr/...">` tiles in the modal with elements you fill via `renderInvoice()` above, and poll `/api/ln/status/:hash` to flip a tile to "paid ✓".

---

## 4. Arkade checkout ($85.21)

`pay.js` → `arkadeBtn` opens `https://arkade.money/`. Replace with your specific Arkade product/order URL so the amount and item are pre-filled. On success, Arkade can webhook your backend to mark the order paid and trigger the ~1-week-faster fulfillment lane.

---

## 5. Security & ops notes

- Keep node macaroons / LNbits admin keys server-side only — never in the browser. Use **Infisical** (see the RIVO project's secrets tab pattern) or env vars.
- Use **invoice (read) keys** for minting, **admin keys** never client-side.
- Set sane `expiry` (e.g. 600s) on invoices and show a countdown on the tile.
- Watch inbound liquidity; for larger amounts ($850+, $2k–$5k) you may need a channel with enough remote balance or an LSP.
- Reconcile Stripe + Lightning into one orders table so fulfillment doesn't double-ship.
```
orders(id, method[card|ln], amount_usd, status, ln_payment_hash, stripe_session, ship_lane)
```

---

## 6. Quick checklist

- [ ] Node up (LND/CLN/managed)
- [ ] Lightning Address resolves (`pay@highermark.xyz`)
- [ ] Invoice API reachable from backend (LNbits/BTCPay)
- [ ] Front-end mints + renders live invoices (replace static SVGs)
- [ ] Arkade order link wired into `arkadeBtn`
- [ ] Stripe link wired into `confirmCard` → `goStripe`
- [ ] BTCPay shout box configured (see `btcpayserver.md`)
- [ ] Secrets in Infisical / env, not in the repo
