Inspiration. Every freelancer and small business lives in the same loop: draft an invoice in one tab, send it, remember to chase it, dig up who paid, issue the odd refund. PayPal has the APIs for all of it, but using them means hand-rolling OAuth, JSON payloads, and state machines. I wanted the commerce equivalent of a good ops hire: tell it what you want in plain language and it does the PayPal work, correctly, through the real API.
What it does. PayPilot turns natural language into PayPal operations. "Invoice Acme Corp $1,250 for design work, due in 30 days, send it" creates a draft invoice and sends it. "Who hasn't paid yet?" lists unpaid invoices with totals. "Refund the last payment from John" searches recent payments and issues the refund by capture id. Eight tools cover the receivables loop: invoice create/send/remind/list/status, payment search, refunds, and an account summary. A self-hosted MCP server exposes the same eight tools over Streamable HTTP, so any MCP client can drive PayPilot too, and a small web UI shows every tool call the agent makes.
How I built it. The core is a PayPal REST client in pure Python (stdlib only): OAuth2 client-credentials, Invoices v2 (create, get, list, send, remind, cancel), Transaction Search for payment lookup, and Payments v2 refunds. All network I/O goes through an injectable transport, so the full test suite runs against an in-memory PayPal simulation with real state transitions and no credentials. One shared tool table drives the agent loop, the MCP server, and the web UI, so all three surfaces behave identically. The agent is a compact ReAct-style tool-calling loop over any OpenAI-compatible chat endpoint.
Challenges. PayPal's Payments API has no list operation, so payment discovery lives in the separate Transaction Search API with its own auth scope and a deeply nested response shape. There is no API-only way to mint a refundable capture id in the sandbox (it needs a completed buyer checkout), so live refund testing is mock-covered with a documented escape hatch. The invoice list endpoint has no status filter, so "who hasn't paid" filters client-side. All documented in the repo's friction log.
Accomplishments. 48 passing tests plus a live sandbox verification: the full invoice lifecycle (OAuth, create, get, list, send, remind, transaction search, cancel) passes 9/9 against the real PayPal sandbox. The live run caught and fixed three real API contract bugs the mocks couldn't (form-encoded OAuth, 201 self-link responses, amount shape). A demo video shows a live agent run completing a create-send cycle, an unpaid-invoice query, and a payment search-and-refund as genuine tool calls.
What's next. Partial-refund UX with explicit confirmation for large amounts, recurring-invoice scheduling, and a reconciliation view that matches payouts to invoices.
Log in or sign up for Devpost to join the conversation.