{
  "markdown": "<div align=\"center\">\n\n<img src=\"docs/cover.png\" alt=\"xupersplit — split expenses, skip the fuss\" width=\"640\" />\n\n# xupersplit\n\n**Split shared expenses without the fuss.** Create a split, share the link, and\nlet everyone add what they paid — balances and who-owes-whom are worked out\nautomatically, with one-tap payments straight from the balance view.\n\n[**split.xuper.fun**](https://split.xuper.fun) · English · [Svenska](README.sv.md)\n\n[![CI](https://github.com/kanylbullen/xupersplit/actions/workflows/ci.yml/badge.svg)](https://github.com/kanylbullen/xupersplit/actions/workflows/ci.yml)\n&nbsp;[![License: MIT](https://img.shields.io/badge/License-MIT-0d9488.svg)](LICENSE)\n&nbsp;[![MCP registry](https://img.shields.io/badge/MCP-registry-f59e0b.svg)](https://registry.modelcontextprotocol.io/v0/servers?search=xupersplit)\n&nbsp;[![Live app](https://img.shields.io/badge/live-split.xuper.fun-0d9488.svg)](https://split.xuper.fun)\n\nNext.js 16 · Supabase · Tailwind v4 · wagmi/viem\n\n<br />\n\n<img src=\"docs/demo.gif\" alt=\"xupersplit demo — create a split, add an expense, then settle up onchain in USDC\" width=\"240\" />\n&nbsp;\n<img src=\"docs/screenshot-pay.png\" alt=\"Pay dialog: a Swish QR with the exact amount already filled in\" width=\"240\" />\n&nbsp;\n<img src=\"docs/screenshot-shares.png\" alt=\"New expense: splitting by shares, a couple counting double\" width=\"240\" />\n\n<sub>Create a split and see who owes whom · a Swish QR with the amount already in it · splitting by shares</sub>\n\n</div>\n\n---\n\n> **Works with AI agents.** xupersplit is an [MCP server](#mcp-server) too —\n> point your assistant at one URL and it can create the split, add what everyone\n> paid and tell you who owes whom. No account, no API key, nothing to install.\n>\n> ```\n> claude mcp add --transport http xupersplit https://split.xuper.fun/api/mcp\n> ```\n\n## What it is\n\nA clean, accountless expense splitter. The **secret link is the key** — anyone\nwith it can add expenses and settle up; no login required. Optional email\nsign-in just makes your splits follow you across devices. Built as a one-prompt\nproject and grown from there.\n\n## Features\n\n- **No account needed.** The unguessable split link (122 bits of entropy) *is*\n  the capability. Sign-in is optional.\n- **Flexible splitting** — equal, weighted shares, or exact amounts, with cent\n  rounding via the largest-remainder method.\n- **Smart settlements** — the minimum set of \"A pays B\" transfers, with\n  **partial payments** (\"pay all or part\") and strike-through once settled.\n- **Don't settle too early** — see who has opened the split and who's marked\n  themselves done; the pay dialog warns if someone hasn't weighed in yet.\n- **Secure splits** *(optional, when signed in)* — bind participants to their\n  accounts: you can only edit your own payment details and enter your own\n  expenses. The creator picks who must log in, who can view, and how people join.\n- **Multi-currency** — enter expenses in any currency with the rate **locked at\n  save** (Kittysplit-style); set a main currency per split. Includes **sats** —\n  run a whole split in bitcoin if you like.\n- **Eight payment methods**, several with genuine one-tap prefill — [see below](#payments).\n- **MCP server** — AI agents can run a whole split over\n  [Model Context Protocol](#mcp-server), with no account and no API key.\n- **Six languages** — English, Svenska, Norsk, Dansk, Suomi, Íslenska\n  (auto-detected, switchable).\n- **Privacy by design** — payment details can be wiped once everyone is square,\n  inactive splits are purged after 6 months, IP hashes deleted within a day,\n  CSV/JSON export, full GDPR policy.\n- **Dark / light / system** theme, cookie-less analytics, discreet cookie notice.\n\n## Payments\n\nxupersplit stores each recipient's payment handle(s) and, wherever a payment\nnetwork exposes an **open, agreement-free** interface, turns the balance row\ninto a real one-tap payment — **prefilled with the exact amount**. No money ever\npasses through xupersplit; it only builds the link/invoice/transaction the payer\napproves in their own app.\n\n| Method | Experience | How |\n| --- | --- | --- |\n| **Swish** 🇸🇪 | QR + app deep link, amount prefilled | Public `app.swish.nu` link + QR endpoint — no merchant contract |\n| **Lightning** ⚡ | QR + `lightning:` link, **exact amount baked in** | LNURL-pay (LUD-16): a lightning address → BOLT11 invoice |\n| **Ethereum / USDC** Ξ | **One-tap prefilled USDC** transfer | WalletConnect (Reown AppKit) — connect, pick chain, approve |\n| **Solana / USDC** ◎ | **One-tap prefilled USDC** SPL transfer | WalletConnect (Reown AppKit) — Phantom/Solflare, recipient ATA auto-created |\n| **Ethereum / Solana address** | Address QR + copy, ENS resolved | `0x…` / `name.eth` / base58 — for any wallet |\n| **Revolut** | Clickable `revolut.me` profile link | Opens the recipient's profile to pay |\n| **Vipps · MobilePay · IBAN** | Stored handle + copy button | No open P2P API — the payer finishes in their own app |\n\n**Why the difference?** Swish exposes a genuinely open prefilled deep link and\nQR endpoint; Lightning's LNURL and EVM/Solana over WalletConnect are open\nprotocols. Vipps\nand MobilePay (now Vipps MobilePay) only offer amount-prefilled flows through\ntheir **merchant** APIs — a business agreement that routes money to a company,\nnot person-to-person — so for those xupersplit does the honest thing and shows\nthe handle with a copy button. If they ever ship an open P2P deep link, wiring\nit in is a small change. PRs welcome. 🤞\n\n> **Crypto is irreversible.** Crypto methods show extra warnings, and **any**\n> method warns (with a date) if the recipient's details were ever changed from\n> what was first entered — anyone with the link can edit them.\n\n## MCP server\n\nxupersplit speaks [Model Context Protocol](https://modelcontextprotocol.io), so\nan AI assistant can create a split, add what everyone paid and report who owes\nwhom — then hand you the link to share. Accountless like the rest of the app:\nno sign-up, no API key.\n\n```bash\nclaude mcp add --transport http xupersplit https://split.xuper.fun/api/mcp\n```\n\nOr point any MCP client at `https://split.xuper.fun/api/mcp` (Streamable HTTP;\nstdio-only clients can bridge via `npx mcp-remote`). Self-hosted instances get\nthe same endpoint at their own `/api/mcp`.\n\nIt also works as a custom connector in **Claude** and **ChatGPT** on the web —\npaste the endpoint, no authentication. ChatGPT needs developer mode switched on\nfirst, or the option to add one isn't there at all. Step-by-step at\n[/mcp](https://split.xuper.fun/mcp).\n\nEleven tools cover the whole lifecycle — `create_split`, `get_split`,\n`add_expense`, `record_payment`, `update_entry`, `delete_entry`,\n`add_participant`, `rename_participant`, `remove_participant`,\n`set_payment_methods`, `update_split`. People are referred to by name and\namounts are plain decimals, so an agent never handles uuids or cents.\n\nThe server is a thin layer over the same RPCs and `money.ts` helpers the web app\nuses, and it only ever holds the anonymous role — which is what keeps *secure*\nsplits (they need a signed-in `auth.uid()`) unreachable over MCP. Full details\nat [/mcp](https://split.xuper.fun/mcp).\n\n## Architecture\n\n- **No service-role key in the app.** All data access goes through\n  `security definer` Postgres RPCs (`split_data`, `save_entry`,\n  `set_payment_methods`, …) where the secret split key in the URL is the\n  capability. RLS is deny-all on every table and direct grants are revoked — the\n  client only ever holds the public publishable key. Schema and every change\n  live in [`supabase/migrations/`](supabase/migrations).\n- **Next.js App Router** + server actions; the client is plain React, no state\n  library. Tailwind v4 with CSS-variable theming.\n- **Thin, keyless API routes** proxy the open payment networks, all\n  same-origin-locked: `/api/swish-qr`, `/api/ln-invoice` (LNURL-pay),\n  `/api/ens` (viem), `/api/fx` (fiat + BTC, with provider fallback).\n- **WalletConnect** is fully gated on a project id — absent, the EVM dialog\n  cleanly falls back to QR + copy.\n- **Privacy & abuse controls** — settle-time payment wipe (opt-out), 6-month\n  purge of inactive splits, per-IP-hash + global create rate limits, and a\n  daily job that flags split-key enumeration attempts.\n\n## Tech stack\n\nNext.js 16 · React 19 · TypeScript · Tailwind CSS v4 · Supabase (Postgres,\nAuth) · wagmi + viem + @solana/web3.js + Reown AppKit · Playwright · Vercel\n\n## Run it locally\n\n```bash\nnpm install\ncp .env.example .env.local   # add your own Supabase URL + anon key\nnpm run dev\n```\n\n`.env.local`:\n\n```\nNEXT_PUBLIC_SUPABASE_URL=https://<your-project>.supabase.co\nNEXT_PUBLIC_SUPABASE_ANON_KEY=<your publishable key>\n# Optional — enables the WalletConnect USDC flow (free id from cloud.reown.com)\nNEXT_PUBLIC_REOWN_PROJECT_ID=<your reown project id>\n```\n\n## Deploy your own\n\nSelf-hostable on the free tiers of **Supabase + Vercel**.\n\n1. **Supabase** — create a project (EU regions keep data in Europe), then apply\n   the schema with `supabase link --project-ref <ref> && supabase db push`\n   (runs every migration in [`supabase/migrations/`](supabase/migrations)).\n   Grab the **Project URL** and **publishable (anon) key**. For optional email\n   sign-in, configure SMTP and the `…/auth/confirm` redirect.\n2. **Vercel** — import the repo, add `NEXT_PUBLIC_SUPABASE_URL` and\n   `NEXT_PUBLIC_SUPABASE_ANON_KEY` (both safe to expose; security relies on RLS\n   + RPCs). Add `NEXT_PUBLIC_REOWN_PROJECT_ID` too if you want WalletConnect.\n   Deploy.\n3. **Custom domain (optional)** — add it in Vercel, point a **DNS-only** CNAME\n   to `cname.vercel-dns.com`, and add the domain's `…/auth/confirm` to the\n   Supabase redirect allowlist if using email sign-in.\n\n## Full self-host with Docker\n\nPrefer to own the whole stack? [`selfhost/`](selfhost) brings up the app **and\nits own backend** — Postgres, auth (GoTrue), the REST/RPC layer (PostgREST) and\na local mailbox — with no external services. The app itself acts as the gateway,\nso the browser only ever talks to one origin.\n\n```bash\ncd selfhost\ncp .env.example .env       # ⚠️ change the secrets — see the notes in the file\ndocker compose up -d --build\n```\n\n- App: **http://localhost:3000**. Sign in with **email + password** (works\n  instantly, no SMTP needed) — or use the magic code, which lands in **Mailpit**\n  at **http://localhost:8025**.\n- **HTTPS** is one flag away: point a domain at the host, set `DOMAIN` +\n  `ACME_EMAIL` and `SITE_URL=https://…` in `.env`, then\n  `docker compose --profile tls up -d --build` — Caddy fetches and renews a\n  Let's Encrypt certificate automatically. Behind NAT or want a wildcard cert?\n  Set `CF_API_TOKEN` (a scoped Cloudflare token) and Caddy uses the DNS-01\n  challenge instead — no port 80 exposure needed.\n- The migrations in [`supabase/migrations/`](supabase/migrations) are applied\n  automatically on first start.\n- `.env.example` ships with **public demo** JWT keys so it runs out of the box.\n  For anything internet-facing, change `JWT_SECRET` + the passwords and\n  regenerate `ANON_KEY`/`SERVICE_ROLE_KEY` (any JWT tool works — sign\n  `{\"role\":\"anon\",...}` / `{\"role\":\"service_role\",...}` with the new secret).\n- Set `APP_PORT` / `MAILPIT_PORT` in `.env` to change host ports;\n  `REOWN_PROJECT_ID` enables the WalletConnect pay buttons.\n\nSee **[`selfhost/README.md`](selfhost/README.md)** for the full guide —\nsecret regeneration, the gateway architecture, Cloudflare DNS-01, a config\nreference and troubleshooting.\n\n## Tests & CI\n\nPlaywright smoke tests (`npm run test:e2e`) run on every PR against a local\nproduction build, gating merges to `main`; the pure split/balance/settlement\nlogic lives in `src/lib/money.ts`.\n\n## Contributing\n\nIssues and PRs are welcome, and so is a bug report from someone who just used\nthe site. Start with [CONTRIBUTING.md](CONTRIBUTING.md).\n\n> **Never post a split link.** A split's URL is its password — anyone who sees\n> it can read and edit that split, and issues are public and indexed. Describe\n> the problem, or make a throwaway split with fake names.\n\n- 🐛 [**Report a bug**](https://github.com/kanylbullen/xupersplit/issues/new?template=bug_report.yml) — or just email **split@xuper.fun** if a GitHub account is a hassle\n- 💡 [**Suggest a feature**](https://github.com/kanylbullen/xupersplit/issues/new?template=feature_request.yml)\n- 🔒 [**Report a vulnerability privately**](https://github.com/kanylbullen/xupersplit/security/advisories/new) — never as a public issue; see [SECURITY.md](SECURITY.md)\n- 🌱 [**good first issue**](https://github.com/kanylbullen/xupersplit/labels/good%20first%20issue) — small, self-contained tasks\n\nMost wanted right now: a real open P2P deep link for **Vipps** or **MobilePay**\nso the amount can be prefilled the way Swish and Lightning already do, plus\nadditional payment rails and translation fixes across the six locales. The\ncodebase is small and fully typed.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n---\n\n<div align=\"center\">\n\nIf xupersplit saved your group some bickering, you can\n\n[![Buy me a beer](https://img.shields.io/badge/Buy%20me%20a%20beer-%F0%9F%8D%BA-9A7BFF?style=for-the-badge)](https://beer.xuper.fun/?from=github)\n\n*built with love, coffee and beer*\n\n</div>\n",
  "bytes": 13212,
  "sha": "95b4f2515a7fdf48785687c57bdf4cc73ef5f04c5c786dbf28014257ae93a06a",
  "repo_slug": "kanylbullen/xupersplit",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_kanylbullen_xupersplit_d13047ee/readme"
}