Inspiration

A Thai durian exporter invoices Chinese buyers in USD/CNY. Money lands late, shorted by hidden fees, sometimes batched across invoices with a cryptic reference like INWARD REMIT 88213. GotPaid already drafts a written chaser letter for these overdue invoices — but some buyers just don't answer letters. We wanted to give the same case a voice.

What it does

GotPaid reconciles cross-border invoice payments to bank deposits with a deterministic 4-pass matcher, and learns each buyer's real payment behavior over time (median days late, typical fee bite). When an invoice goes unanswered, calle_chaser.py has Claude draft a call goal — tone scaled by how far this invoice is outside the buyer's normal pattern — then CALL-E places the call and runs the conversation. The result comes back structured: task completion, confidence, and a full transcript, ready to reconcile against the next bank deposit.

Real result from our own test call: Nanning Golden Fruit Trading, invoice 105 days overdue against their usual ~40-day pattern. CALL-E called, got a live representative, and secured a confirmed payment date — task completed, 0.95 confidence.

How we built it

  • Claude drafts the call goal from the invoice + the buyer's learned payment profile
  • plan_call → run_call → get_call_run polled live, streaming ringing → connected → what each side said
  • Safety gate: exactly like our letter flow (sendNow=False), a real call only happens behind an explicit --confirm flag. Planning costs nothing and dials nobody.
  • Region workaround: CALL-E dials SG/US/AU/IN, not Thailand. A small Cloudflare Worker (twiml-forward/) relays the call to the real Thai number instead of faking the demo.

Challenges we ran into

Finding the region limit in the first place — plan_call surfaced it cleanly in clarifying_questions, which is what made the relay workaround findable instead of a silent dead end. Live speech-to-text also self-corrects mid-sentence in real time, which we kept in the demo rather than editing out — it's what a real, unscripted call actually looks like.

Accomplishments that we're proud of

A real phone call, to a real number, about a real (synthetic-data) overdue invoice, that got a confirmed payment date back — automatically extracted and saved, no human had to listen to the recording to find it.

What we learned

The trust boundary we'd already built for letters.py (sendNow=False) and esign.py (draft-only signature folders) turned out to be exactly the right shape for a phone call too — "agent proposes, human confirms" didn't need reinventing for voice, just extending. We also learned to treat a platform's own error messages as data: CALL-E's clarifying_questions field told us plainly that Thailand wasn't a supported region, which is what pointed us at the relay-Worker fix instead of a dead end.

What's next for GotPaid — CALL-E Voice Chaser

Broader region coverage as CALL-E expands, and wiring the extracted payment date straight back into GotPaid's reconciliation engine so a confirmed call outcome updates the dashboard the same way a bank deposit match does.

Built With

Share this project:

Updates

Submission history