-
-
task_completed: true, confidence 0.95 — a confirmed payment date, extracted and saved automatically, not just "call attempted."
-
GotPaid's dashboard: invoice INV-1111, 105 days overdue and unpaid — the case CALL-E was given to chase.
-
The real call transcript — 105 days overdue, and the buyer confirms a payment date of September 20.
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_runpolled 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--confirmflag. 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
- api
- call-e
- claude
- cloudflare
- foxitapi
- javascript
- pages
- python
- webmcp
- workers
Log in or sign up for Devpost to join the conversation.