Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
Four AI agents quote the job, bill it through PayPal, chase the payment, and release the work only when PayPal says it's paid.
FinanceTypeScript · HTMLGitHub @shrestha-droidConnection unstableOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Four AI agents that quote a job, bill it through PayPal, chase the payment, and release the work only when PayPal says it's paid. Your clients' AI assistants can hire you too.
Built for the PayPal AI Hackathon. Sandbox only. No real money moves.
Live demo: https://branch-pay.onrender.com (free Render instance: the first load after a quiet spell can take about a minute while it wakes up).
Freelancers and small agencies don't lose money on the work. They lose it on the loop around the work: writing the quote, sending the invoice, chasing late payments, and deciding when it's safe to hand over the files. Hand over too early and you might never get paid; hold on too long and the client walks.
Branch Pay hands that loop to a crew of AI agents, and keeps a human on every decision that moves money.
Client (a person in the dashboard, or their AI assistant over MCP)
|
v
[Scoper agent] --> fixed-price quote. Price cap enforced in code; injected instructions reported and ignored
|
APPROVE <-- a human (bill in full, or 50% deposit first), or a spending limit the human set
|
v
[Biller agent] --> creates + sends a PayPal invoice (tool calling; it cannot choose amounts or recipient)
|
| not paid yet? [Collector agent] --> writes a reminder, PayPal emails it (on its own, max 3)
v
PayPal --> client pays (webhook INVOICING.INVOICE.PAID, polling as a fallback)
|
|-- deposit paid --> [Builder agent] builds the site; client gets a WATERMARKED preview
| balance paid --> final files unlocked + downloadable
'-- paid in full --> [Builder agent] builds and unlocks the site
REFUND (human only) --> money back through PayPal, the deliverable locks again
Until PayPal confirms payment, the deliverable answers HTTP 402 Payment Required with a machine-readable PayPal payment link.
| What it does here | |
|---|---|
| PayPal Invoicing API v2 | Create, send, remind, cancel, read status, record payments and refunds. The deposit plan uses native partial payments (allow_partial_payment + minimum_amount_due) where PayPal offers them, and otherwise a deposit invoice plus a balance invoice (PayPal limits partial payments by the merchant's country). Hand-written REST in src/paypal.ts, so every call is visible. |
| PayPal Payments API v2 | Refunds money the client paid through PayPal (/v2/payments/captures/{id}/refund). |
| PayPal Webhooks | INVOICING.INVOICE.PAID / CANCELLED trigger an instant check. Signatures verified with verify-webhook-signature when PAYPAL_WEBHOOK_ID is set. |
| PayPal OAuth 2.0 | Client-credentials token, cached until near expiry. |
| Gemini (Vercel AI SDK) | Scoper: structured quote + a list of injection attempts it ignored. Biller: tool calling. Collector: reminders whose tone fits how long the client has waited and what payment unlocks. Builder: the HTML deliverable. |
| Model Context Protocol | /mcp/<workspace> is an MCP server (Streamable HTTP). A client's AI assistant can request_quote, get_job and list_jobs. It cannot approve, pay or refund. |
| AG Grid | The Ledger: every quote, invoice and payment with filters, sorting, quick search, a totals row and CSV export. |
| Render | One-click deploy from render.yaml. |
Open Connect an AI agent in the app to get your workspace's MCP URL, then:
claude mcp add --transport http branch-pay <your MCP URL>npx @modelcontextprotocol/inspector, choose Streamable HTTP, paste the URL.Then ask: "Use Branch Pay to get me a quote for a one-page website for my bakery. Bill Jane Doe at <sandbox buyer email>." The job appears in your pipeline. You approve; the agent can then fetch the PayPal pay link for its human, and the deliverable link once PayPal reports payment.
People stay in charge on both sides: the agency approves, the buyer's human pays. Optionally set AUTO_APPROVE_UNDER_USD to let small jobs run end to end within a limit you chose in advance (a spending mandate, enforced in code).
| Guardrail | How |
|---|---|
| The AI never chooses who is billed or how much | The Biller's tools accept only a note and payment terms. Amounts, deposit and recipient come from the approved quote on the server. |
| Hard price cap | Any quote is scaled under MAX_QUOTE_USD in code, rounding included (npm test). |
| Humans own the money moves | Nothing is invoiced until a person (or their pre-set limit) approves. Refund and cancel have no AI tool at all. |
| Prompt injection can't reach an action | The client text is untrusted data. The Scoper reports injected instructions, but safety never depends on that: the text can only influence a quote that code clamps and a human approves. Try Try a prompt injection in the app. |
| Webhooks are a nudge, not the truth | A webhook only makes the server re-read the invoice from PayPal, so a forged event can't unlock anything. |
| No reminder spam | The Collector writes; code decides when, max 3 per payment. |
| Idempotency | The job id is the PayPal-Request-Id, so a retry never creates a second invoice. Refunds use one key per payment. |
| AI-written HTML is sandboxed | Served with Content-Security-Policy: default-src 'none' in a sandboxed iframe. Everything in the UI is HTML-escaped. |
| Public-demo hygiene | Each browser gets its own workspace; quotes are rate limited per visitor and per day; sandbox only (the server refuses the live PayPal API). |
| Crash-safe | A job interrupted mid-step goes back to a retryable state on restart. |
You need Node 20+.
https://www.sandbox.paypal.com.git clone https://github.com/shrestha-droid/branch-pay
cd branch-pay
npm install
cp .env.example .env # then fill in the keys
npm start
Open http://localhost:3000. Run npm test for the payment-rule tests.
Click Deploy to Render above, paste your PayPal sandbox and Gemini keys when asked, and you get a public URL. Then, optionally, add a sandbox webhook in the PayPal developer dashboard pointing at https://<your-app>.onrender.com/api/paypal/webhook with INVOICING.INVOICE.PAID and INVOICING.INVOICE.CANCELLED, and set its id as PAYPAL_WEBHOOK_ID.
On Render's free plan the instance sleeps after 15 minutes idle and its disk is not persistent, so demo jobs are cleared on restart.
AUTO_REMIND_MINUTES=2), or click Send reminder now.src/config.ts settings, price cap, limits, sandbox-only guard
src/paypal.ts PayPal OAuth, Invoicing, Payments (refunds), webhook verification
src/agents.ts Scoper, Biller, Collector, Builder
src/mcp.ts MCP server for buyers' AI agents
src/store.ts jobs in data/jobs.json, plus the pure payment rules
src/server.ts HTTP routes, webhooks + polling, auto-reminders, rate limits, the 402 gate
src/*.test.ts npm test: price cap, deposit, payment transitions, reminder schedule
public/index.html the web UI (plain HTML + AG Grid from a CDN, no build step)
render.yaml Render Blueprint
MIT. See LICENSE.