Stripe not connected
Add the Stripe secret and webhook signing secret in More → Cloud → Secrets, then run the initial import below. The server functions, database schema, and this UI are already wired for live data.
—
—
—
—
Webhook updates are near real time, with hourly reconciliation as a fallback. The hourly job runs server-side even when no browser is open.
The import is idempotent (reruns upsert by Stripe ID, no duplicates), paginates within runtime limits, and handles rate limits with bounded retries. A partial import is never marked successful — the sync state stays failed until a full run completes.
The endpoint POST /api/sync is implemented and protected by a CRON_SECRET bearer token. It reuses the real full-import implementation, prevents overlapping runs via a durable lease, paginates within runtime limits, handles rate limits with bounded backoff, never marks a partial import successful, and records start/completion/counts/failures in sync_jobs.
Scheduler setup
This project deploys to a Cloudflare Workers runtime. Configure an hourly Cron Trigger that sends an authenticated request to the endpoint — for example a worker scheduled handler or an external scheduler (Google Cloud Scheduler / cron-job.org) issuing:
curl -X POST https://<your-domain>/api/sync \ -H "Authorization: Bearer $CRON_SECRET"
Add CRON_SECRET in More → Cloud → Secrets (a long random string). The secret is never placed in a URL or in frontend code.
No owners
Bootstrap the first owner below.
Approve a new owner
Approving an owner requires that person to have already signed up at the sign-in page (email/password). No self-service sign-up grants dashboard access.
First-owner bootstrap (one-time)
Until at least one owner exists, no one can view data or approve owners. To create the very first owner:
- Sign up at the sign-in page using your owner email and password (email/password auth).
- Open More → Cloud in this builder and run the one-time bootstrap SQL below against the database (it inserts your user as the first owner). Replace the email with the exact one you signed up with.
- Sign in again — you will now have owner access and can approve additional owners from this page.
-- Run once in More → Cloud (SQL editor) to bootstrap the first owner.
-- Replace the email with the address you signed up with.
INSERT INTO public.owners (user_id, email, approved_by, approved_at)
SELECT u.id, u.email, NULL, now()
FROM auth.users u
WHERE lower(u.email) = lower('YOUR_OWNER_EMAIL@example.com')
ON CONFLICT (user_id) DO NOTHING;Only the very first owner is created this way. Every subsequent owner is approved by an existing owner from this page — users can never approve themselves.