# Where the pieces go The integration is the same in every framework: the browser opens sub3's hosted pages; your server verifies the session token and asks `GET /v1/access`; if you sell packs, the server credits receipts from `GET /v1/orders`. ## Browser: React, Vue, Svelte, plain JS Copy [node/public/sub3.js](node/public/sub3.js). It does not touch `window` when imported, so it is safe with server-side rendering. Call `openSub3` directly inside a click handler, or browsers block the popup. - React: call it in `onClick`; read redirect results with `readSub3Result()` in a `useEffect` on mount. - Vue: a method bound with `@click`; `readSub3Result()` in `onMounted`. - Svelte: `onclick`; `readSub3Result()` in `onMount`. Send the login `token` to your server (`Authorization: Bearer …`). After a checkout, send `{ payer, orderId }` to your server and render what it answers; never unlock anything from the checkout result itself. The flow is in [node/public/app.js](node/public/app.js) (`signIn`, `buy`, `receive`). Do not serve the page that opens the popup with `Cross-Origin-Opener-Policy: same-origin`. ## Server: Express, Next.js, SvelteKit, Hono, any Node server Copy [node/sub3.mjs](node/sub3.mjs) and call it from your routes: - `verifySession(config, token)` → the user's address, or an error with `status` 401 (sign in again) or 503 (retry). - `getAccess(config, user)` before anything paid; `getAccess(config, user, { fresh: true })` after a checkout. - `afterCheckout(config, db, user, { payer, orderId })` when the browser reports a checkout result. - `syncPacks(config, db, user)` on sign-in and when showing the balance, if you sell packs. `config` is `{ api, site, origin, product }` (see [node/config.mjs](node/config.mjs)). Keep one process-wide module instance so the access cache and the JWKS cache are shared. Next.js route handlers and SvelteKit endpoints receive a Fetch `Request`: read the header with `request.headers.get('authorization')`. `node/ledger.mjs` uses `node:sqlite` (Node 22.13+, a persistent disk). On Postgres, MySQL or D1, keep the same primary keys — `receipts (chain_id, contract, payer, order_id)`, `usage (user, cycle)`, `operations (user, id)` — and the same transactions. Edge runtimes cannot use `node:sqlite`. ## Python, Go, Ruby, Workers No SDK is needed; everything is HTTP and a standard JWT: 1. Verify the token with any JWT library supporting EdDSA and a JWKS URL (`/.well-known/jwks.json` on the API): algorithm `EdDSA` only, `iss` = the sub3 site, `aud` = your origin, not expired. `sub` is the address. 2. `GET /v1/access?product=acme/app&user=
`; cache 30–60 s; refresh after checkout. Treat 429 and 5xx as "unknown", never "unpaid". 3. For packs, `GET /v1/orders?product=acme/app&user=
` and insert each confirmed `kind: "pack"` order into a table keyed by `(chainId, contract, payer, orderId)` in the same transaction that adds its `credits` (a decimal string; use arbitrary-precision integers). The full contract of each endpoint is in `/llms.txt`.