Inspiration
Every SaaS or subscription business loses revenue the same quiet way: a card expires, a payment fails, and the automated dunning email goes unread. The customer didn't intend to cancel — they just never saw the message.
I face this personally running community programs where missed payments mean lost participants. Email open rates for billing issues hover around 20%. A phone call gets answered. That gap is what Recover is built to close.
What it does
Recover is an AI-powered payment recovery agent that uses CALL-E to place outbound phone calls to subscribers with failed payments — having a real, structured conversation to understand their situation and capture their intent.
After a call, the agent surfaces one of three advisory outcomes to a human operator dashboard:
- Retry now — customer confirmed they want the charge re-attempted
- Update card — customer wants to switch payment methods
- Pause subscription — customer requested a grace period
A human operator reviews and confirms before any financial action is executed. Nothing is done autonomously.
How we built it
The stack is intentionally minimal and focused on reliability:
- Next.js 16 (App Router) — API routes handle call orchestration, webhook ingestion, and the operator dashboard
- CALL-E TypeScript SDK — call creation with a structured
resultSchemathat extracts a typedPaymentRecoveryDecisiondirectly from the conversation - Stripe Webhooks — trigger recovery flows on
invoice.payment_failedevents - SQLite (in-memory) — lightweight state machine tracking call lifecycle:
initiating → active → pending_confirmation → completed
The most interesting architectural decision was the webhook re-fetch pattern:
since CALL-E doesn't currently sign webhook payloads, the app never trusts incoming
webhook bodies. Every webhook triggers an authoritative re-fetch of the call via
GET /v1/calls/{id}, binding the result to the exact local call record and stored
subscriber destination before anything is recorded.
Challenges we ran into
Webhook security without signing — No signing secret means you can't verify the webhook sender client-side. The solution — re-fetching from the authenticated API — is the right mitigation but isn't documented as a recommended pattern. We had to arrive at it independently and implement it as a security requirement.
Idempotency key lifecycle — After a call is rejected pre-dial (e.g. missing sender disclosure), reusing the same idempotency key throws an error. The distinction between "safe to issue a new key" vs "must reconcile first" isn't walked through in the docs with a concrete example.
Region support discoverability — Ghana isn't currently a supported calling region, and this only surfaces as a rejection at call-creation time — there's no pre-flight way to check supported regions from code. CALL-E's Discord support team pointed us to the US test hotline as a workaround, which allowed us to complete the integration.
Accomplishments that we're proud of
Getting a structured, validated payment decision — retry_now, update_card, or
pause_subscription — out of a natural phone conversation with zero custom NLP is
genuinely remarkable. CALL-E's resultSchema handled all of that.
We're also proud of the safety architecture: a bounded retry chain, destination binding verification, idempotency throughout, and a strict human-confirmation gate before any financial action. It's a reference implementation that takes the "just a demo" shortcuts seriously.
What we learned
The AI part of an AI calling agent is the easy part. The hard part is the surrounding reliability infrastructure: idempotency, deduplication, bounded retry logic, and making sure you never act on an ambiguous or unverified outcome.
We also learned that the most impactful documentation gap for early CALL-E adopters isn't the happy path — it's the edge cases: rejected calls, failed verifications, and what to do with a webhook you can't cryptographically verify.
What's next for Recover – AI Payment Recovery Agent
- Real Stripe integration — execute confirmed retries and card-update sessions automatically after human approval
- Webhook signing — once CALL-E ships signed webhooks, remove the re-fetch
overhead for verified deliveries
- Multi-region support — expand beyond US as CALL-E adds more supported regions
- Analytics — track recovery rates, call outcomes, and churn reduction over time
Built With
- call-e-sdk
- next.js
- node.js
- sqlite
- stripe
- tailwind-css
- typescript
Log in or sign up for Devpost to join the conversation.