Inspiration

In export trade, one chat line ("Can you do DDP instead of CIF?") silently moves duty, VAT, freight, insurance and risk between seller and buyer. Small exporters handle this in spreadsheets, retype the invoice by hand, and find the mistake after the buyer has paid. General AI assistants make it worse: they will happily invent a duty rate or a freight price. We wanted an agent that is useful precisely because it refuses to guess.

What it does

  • You paste a buyer request in plain English. A language model (Gemini, free tier) extracts the product, HS code, quantity, unit price, ports, Incoterm and container. Every extracted number or code is checked against the original text; anything not literally present is dropped and flagged.
  • A deterministic engine prices every cost line from clearly labelled sample tables and colours it by who pays under the selected Incoterms 2020 rule: blue for seller, amber for buyer.
  • Anything it does not know stays "unknown – needs input" (for example inland haulage, which depends on the factory). Unknown propagates to derived lines (insurance, duty, VAT) instead of becoming 0, and the invoice button stays blocked.
  • One click issues a real PayPal invoice (Invoicing v2, sandbox) for the seller's share.
  • When the buyer switches the term (CIF → DDP), the app re-quotes and offers a single action: cancel v1 and issue v2. PayPal stays the system of record; the app shows a diff of which lines changed payer, the new delivery point and risk transfer, and the invoice delta (in the demo: +USD 5,903.29).
  • Refresh pulls the invoice status back from PayPal, and a timeline keeps an audit trail of every version.

How we built it

  • Node.js + Express, a single-page vanilla JS UI (no build step).
  • src/agent.js: Gemini REST adapter with output verification and a regex fallback.
  • src/quote.js / src/incoterms.js: an 11-rule Incoterms 2020 allocation matrix and a landed-cost engine with unknown propagation and quote diffs.
  • src/paypal.js: PayPal Invoicing v2 client (OAuth client credentials, create draft, send, cancel, get) plus a mock mode with the same response shapes.
  • src/deals.js: invoice versioning. The new draft is created first, the old invoice is cancelled second and the new one is sent last, so a failure never leaves a deal without a valid invoice.
  • 49 automated tests (node --test).

Challenges we ran into

  • PayPal's KR→KR payer restriction. Our sandbox business account is Korean, and sending an invoice to a Korean sandbox buyer fails with KOREAN_MERCHANT_KOREAN_PAYER_RESTRICTED. Exporters invoice foreign buyers anyway, so the demo uses a non-KR buyer email, which PayPal accepts without the recipient having a PayPal account.
  • NET_15 due dates. PayPal rejects a NET_15 invoice whose due date is not exactly invoice date + 15 days ("Due date is not valid for the given term_type"). We now derive the due date from the invoice date.
  • Keeping the LLM out of the maths: every amount comes from the engine, never from the model.

Accomplishments that we're proud of

  • A real sandbox round trip: invoice v1 sent → cancelled → v2 sent, with the hosted PayPal invoice page showing the DDP note "Supersedes v1 (CIF)".
  • The agent says "I don't know" in the right places, and the UI makes that visible instead of hiding it.

What we learned

  • Incoterms are a cost-allocation problem as much as a legal one. Showing the payer next to every amount makes a term change understandable in seconds.
  • Treating PayPal as the system of record (new version, never an edit) makes the audit trail simple.

What's next

  • Real rate sources (forwarder quotes, official tariff APIs) behind the same "labelled source or unknown" contract.
  • Partial payments and deposits, and buyer-side acceptance of a new version.
  • More destination VAT and duty regimes.

Built with

Node.js, Express, PayPal Invoicing API v2 (sandbox), Google Gemini API (free tier), vanilla JavaScript, node:test.

AI tools disclosure

Anthropic Claude (via Claude Code) proposed the idea and drafted the code, tests, README, demo script and this write-up. The entrant reviewed, ran and approved the work. At runtime, Google Gemini extracts fields from the buyer's message only; it never computes or supplies amounts. The demo narration is text-to-speech (Microsoft Edge neural voice). All rates are sample data for demo, not official tariffs or legal advice.

Links

Share this project:

Updates

Submission history