-
-
Inbox: paste a customer request, Quotely extracts the facts and drafts the quote with AI.
-
AI quote builder: every line matched to your own price list. No match, no price, no approval.
-
The PayPal invoice the customer receives (sandbox). Deposit first, balance later, one invoice per stage.
-
Payment received: verified against PayPal before the quote moves on. Webhook + reconciliation, same result.
-
Quote settled: deposit and balance paid, reminders scheduled by the nudge agent and skipped once paid.
-
AG Studio dashboard: KPIs, cash movement, money-flow funnel, who owes what, agent activity, receivables.
The gap between "yes" and "paid"
Every small service business knows this moment. A customer says yes. Then comes the part nobody likes: writing the quote by hand, asking for a deposit, waiting, writing the final invoice, waiting again, and sending the awkward "just checking in on that payment" email.
For an equipment rental company, a caterer, an events agency or an AV installer, that gap is where money leaks: late deposits, forgotten balances, evenings spent on admin. I have spent the last months inside exactly this kind of company, a B2B rental business in Milan, watching quotes being typed from emails and payments being chased on WhatsApp. Quotely is the tool I wished they had.
What Quotely does
From request to cash, on autopilot.
- A request comes in as free text: a pasted email or a form message.
- AI drafts the quote. It extracts the customer, dates, location and line items, and matches every line against your own price list. It never invents a price: anything it cannot match is flagged "Needs a price" and blocks approval until a human fixes it.
- You review and approve. Edit quantities, fix an email, change the deposit percentage.
- PayPal collects the deposit. On approval Quotely creates and sends a deposit invoice (default 30%) through the PayPal Invoicing API v2. The customer pays it the way they already know.
- Payment is detected twice. A PayPal webhook (
INVOICING.INVOICE.PAID, signature-verified) and a reconciliation pass every 30 seconds. Neither path trusts the event alone: Quotely re-reads the invoice from PayPal and checks status and amount before marking anything paid. Both paths call the same idempotentmarkInvoicePaid, so the result is identical whichever arrives first. - Job done, one click sends the balance. Same flow, same guarantees. One invoice per stage, never duplicates; a retry reconciles the existing invoice instead of creating a second one.
- A nudge agent chases late payers. It schedules friendly reminders before a deposit is due and after a balance is late, drafts them with AI, logs every decision (sent / scheduled / skipped / failed) and stops the moment PayPal confirms payment. "Skipped · already paid" is a feature, not a bug.
- Money, moving. An AG Studio dashboard shows outstanding, overdue, deposits secured, cash collected, weekly cash movement, a money-flow funnel, "who owes what", the agent's activity feed and a receivables ledger. Three custom React widgets, a fully themed grid, and real Edit mode: drag a widget, resize it, the layout is saved.
Try it: the live demo runs on the PayPal sandbox with seeded data for a fictional company, "Northstar Rentals". Paste a request in the Inbox, draft it with AI, approve it, and open the "Customer's payment page" link: that is a real PayPal sandbox invoice.
How it's built
- Next.js 16 (App Router) + TypeScript + Tailwind 4, started from the official PayPal × AG Grid hackathon boilerplate.
- PayPal REST APIs: OAuth client credentials, Invoicing API v2 (create draft, send, get, list), webhook signature verification (
/v1/notifications/verify-webhook-signature). Sandbox host hard-coded on purpose: this app can never touch live money. - AG Studio 3 for React: one report, one page, 24-track layout,
studioTheme.withParamsfor the dark "Obsidian × Lime" theme,createWidgetsfor the three custom widgets (quotely-debtor-scoreboard,quotely-money-funnel,quotely-nudge-activity), native KPI, line chart, grid and donut for the rest, initial state saved so the page never opens empty. - OpenAI (structured JSON output) for request extraction and reminder drafting. The model only ever sees item names and quantities, never prices: pricing is a deterministic match against the price list.
- Prisma + PostgreSQL on Render, money stored as integer cents, every state transition written to an activity log with its actor (operator, PayPal, agent).
- Payment detection:
POST /api/paypal/webhook+POST /api/paypal/reconcile(shared-secret header), both converging on the same idempotent function. Quote detail and dashboard pages poll reconciliation every 30 seconds while open, so the demo works even without a scheduler. - Design system first: tokens, type scale (Manrope + IBM Plex Mono), money-state colours, motion spec, all documented in
docs/design-system.mdbefore a single component was written.
Challenges
- Never show "paid" from an unverified event. Webhooks can be replayed, delayed or arrive before the invoice is readable. The fix was structural: the webhook is only a hint; the invoice is always re-fetched from PayPal and the amount compared before any state change.
- Two invoices, one quote, zero duplicates. Deposit and balance are separate PayPal invoices with their own lifecycle. Retries, double clicks and slow networks all had to converge on "reconcile the existing invoice", never "create another one".
- Making an AI that refuses to guess. The most useful thing the extraction model does is admit when it does not know a price. Partial matches ("2 items matched, 1 needs a price") turned out to be the most honest UX in the product.
- AG Studio theming at the edges. A few theme parameters do not exist or behave differently from the design doc (chrome background, per-series dash patterns, y-axis ticks). Every substitution is documented in the README so the dashboard looks intentional, not approximate.
- Reminder double-fires. Changing a reminder rule used to leave an orphan scheduled reminder behind. Now every send cancels any other scheduled reminder for the same rule and quote, and rule changes reschedule.
What I'm proud of
- A complete quote-to-cash loop that really moves money (sandbox) end to end: request → AI draft → PayPal deposit → verified payment → balance → verified payment → settled, with an audit trail at every step.
- The nudge agent's restraint: it schedules, it drafts, and it steps aside the second PayPal says the money is there.
- The dashboard: not a bolt-on chart page but a themed, customisable AG Studio canvas with custom widgets that read like part of the product.
- Shipping it, deployed, seeded and webhook-registered, in a single day of focused work with AI pair programming, from a design doc to a public URL.
What I learned
Payments logic is mostly about what you refuse to believe. The product got better every time I removed a shortcut: no price guessing, no trusting a webhook body, no "mark as paid" button. The same discipline applied to the agent: the most valuable automation is the one that knows when to stop.
What's next
- Settings for deposit percentage and payment terms per customer.
- Real email delivery for reminders (today they are drafted and logged, not sent) with PayPal's own reminder as a fallback.
- Multi-currency and tax lines on invoices.
- A customer portal page that shows quote, invoices and payment status in one place.
- Packaging the nudge-agent as a reusable module for any PayPal Invoicing merchant.
Built by Jacopo Gonzales, Gonzales Advisory, Italy. Solo project, PayPal AI Hackathon 2026.
Built With
- ag-grid
- ag-studio
- next.js
- openai
- paypal-invoicing-api
- paypal-webhooks
- playwright
- postgresql
- prisma
- react
- render
- tailwind
- typescript
Log in or sign up for Devpost to join the conversation.