Inspiration

Freelancers and small teams lose hours every week on billing admin — opening a dashboard, filling fields, copying a link, then going back to check whether the customer actually paid. Every invoice is a context switch away from the real work.

What it does

Type one sentence in plain English and get a real, payable PayPal sandbox payment link back.

Type: "Create a 25 dollar payment link for a logo sketch"

The copilot:

  1. sends your sentence, plus a strict JSON schema, to an LLM;
  2. receives back a typed action - {action: "create_order", params: {amount: 25, currency: "USD", description: "logo sketch"}};
  3. exchanges the PayPal sandbox client id + secret for an OAuth 2.0 token;
  4. calls POST /v2/checkout/orders and gets back a real PayPal order;
  5. renders the order id, status, amount and a working payment link in the chat.

Tap "Open payment link" and you land on the real PayPal sandbox checkout showing the exact amount. Nothing is mocked — every order id, status and dollar figure comes straight from PayPal's API response.

It also handles natural variations: "Bill Mike Smith 40 dollars for the landing page" and "Create a 15 dollar payment link for a blog post" both produce real orders. Ask "what invoices are outstanding?" and it lists what PayPal reports.

How I built it

  • Browser: a single-page chat UI, no framework, no build step.
  • Server: zero-dependency Node.js using only the built-in http and fetch. Nothing to npm install.
  • AI layer: an OpenAI-compatible /chat/completions call with temperature 0 and response_format: json_object. The system prompt pins the exact action schema, so the same sentence always maps to the same typed action instead of free-form prose.
  • PayPal layer: OAuth 2.0 client-credentials token, then POST /v2/checkout/orders (payment link).
  • Secrets stay server-side: the PayPal secret and AI key live in .env and are never sent to the browser.

Design decisions

  • The AI output is a typed contract, not text. The model decides what to do; the PayPal layer decides whether it is allowed. That boundary is what keeps an LLM honest when it touches real payments.
  • Failures are never silent. PayPal's own error body is surfaced in the chat verbatim.
  • Graceful degradation. Requests needing a formal invoice fall back to a real, payable payment link when the Invoicing scope is unavailable.
  • Zero dependencies means the whole thing runs with node server.js on any machine.

Challenges I ran into

A fresh PayPal sandbox app does not automatically grant every API scope. The Invoicing endpoints returned 403 NOT_AUTHORIZED while Orders worked fine. I verified this with a probe against /v1/oauth2/token, /v2/checkout/orders and /v2/invoicing/invoices, then designed around it: the copilot prefers the Orders API for anything billable, and falls back to a real payment link if an invoice request hits a missing scope.

Accomplishments I'm proud of

  • Both PayPal and AI are central, not decorative.
  • Zero runtime dependencies.
  • Credentials stay server-side.
  • Every response is real — the UI surfaces PayPal's own id, status and pay link.

What I learned

Constraining an LLM to a strict JSON schema with temperature 0 makes agent behaviour predictable enough to drive a payment API safely. Separating intent (the model) from authorisation (the API) is what makes that trustworthy.

What's next

The same typed-action contract extends naturally to payment reminders, recurring billing, multi-currency invoices and refunds without touching the UI.

Built With

Share this project:

Updates

Submission history