Jenny & Sam Support Deck
Vapi × coinbase

Working prototype

Meet Jenny — and Sam.

A phone-based voice agent for Coinbase support, in two voices — grounded in what Coinbase already publishes, honest about what it doesn't, and never leaves a call empty-handed: unresolved issues become a real ticket, so the customer knows they were heard.

"What you're about to see is a working prototype — an actual phone number, not mockups. Two real scenarios, then I'll hand you the phone."

02 / 9

But, first note that this is not a IVR problem.

Most callers already tried the article and already called support. Nobody solved it, even after listening.

Few findings

CFPB · federal complaints

Fraud / scam — 24%
Funds not available — 22%
Other — 54%

7,775 total, since 2011

Reddit — real posts on r/Coinbase

Account restriction — 35%
Withdrawal delay — 24%
Other — 41%

37 real posts found on Reddit

Fraud, withdrawal delays, account restrictions — the categories above — already have a real, documented fix. We voice it. We can't add self-service options or operations people. We can make sure no call disappears without a trace.

I tested this with real people, too — coworkers at NYC coworking spaces who'd hit these exact problems. All of them agreed on the same thing: our new Vapi IVA is faster, but it isn't actually more helpful until Coinbase resolves the issue behind the ticket it already opened.

03 / 9

Try it yourself

Two voices, one flow. Ask any of these.

Same prompt, same knowledge, same backend — only the voice config differs, to show the assistant isn't married to one voice.

Live now · Jenny Vapi voice "Emma" +1 (213) 699-1138 Real call, real answers, real ticket if needed.
Live now · Sam Vapi voice "Sid" +1 (213) 429-9242 Identical flow, male voice — same prompt, same tools.
01"I think someone got into my account."
02"My account's restricted and nobody's telling me why."
03"My account got closed — how do I get my money out?"
04"Why do withdrawals take so long?"
04 / 9

Try it yourself — every topic

All 8, not just the 2 demoed.

Every category below was actually researched against help.coinbase.com — 6 have a real page behind them, and 2 honestly don't. That absence is a finding, not a gap we didn't get to.

Fraud / compromised account

Documented

Withdrawal / transfer delays

Documented

Account restrictions

Documented

False-positive fraud flag

No fix

No page addresses "you flagged my real transaction" — confirmed absence, not unresearched.

Support unresponsive / no escalation

No fix

Coinbase publishes no internal escalation channel — a ticket is the honest, useful thing this call can offer.

Identity verification (KYC)

Documented

App bugs / technical issues

Documented

Fees / pricing

Documented
05 / 9

Demo 1 of 2 · Fraud & compromised account

The original procedure, the script, the call.

help.coinbase.com — Lock or unlock your compromised account

help.coinbase.com — "Lock or unlock your compromised account" (real page, screenshotted live) Read the full article ↗

Real call — actual transcript, 2026-09-17

Caller"I think someone's gotten into my account — there's a withdrawal I never made."

JennyAI disclosureName personalization"I hear you, Vighnesh. That sounds really concerning. Before we go further, I want to be upfront — this call may be recorded, and you're talking with Jenny, our AI support assistant, not a live person. Is it okay if we keep going?"

Caller"Yes."

CallerTurn-taking"First, can you help me, like, how to lock?"

Jenny"Absolutely. In the Coinbase app, tap Account and Settings, then Security — there you'll see Lock Account."

···

CallerComplex email"It's V-I-G-H-N-E-S-H, b, b, h-u-r-i, at gmail dot com."

Jenny"Let me confirm — b as in bravo, b as in bravo — is that right?"

Caller"No — the two b's are actually d, for dog."

Jenny"Thanks for clarifying — d as in dog, d as in dog. Is that correct?"

···

Jenny"Your ticket is created, ID C-B dash 9-D-6-0-1-2-B-6. You're very welcome, Vighnesh."

Recording — actual call, 4:45

Recorded live through the deployed assistant, not staged.

06 / 9

Demo 2 of 2 · Account restriction

The original procedure, the script, the call.

help.coinbase.com — Coinbase account restrictions

help.coinbase.com — "Coinbase account restrictions" (real page, screenshotted live) Read the full article ↗

Real call — actual transcript, 2026-09-17

Caller"Hi, Jenny. I am not able to access my account."

JennyAI disclosure"I hear you can't access your account. Before we go further, I want to be upfront — this call may be recorded, and you're talking with Jenny, our AI support assistant, not a live person. Is it okay if we keep going?"

Caller"Yes."

···

CallerContext retention"Yeah — but can you give me a minute? There's someone at the door."

Jenny"Of course, take your time. Just let me know when you're ready to continue."

Caller"Okay, I'm back."

Jenny"It sounds like you might have been cut off there — can you tell me again what's happening with your account?"

Caller"No — it's restricted. I can't buy, I can't sell."

···

CallerComplex email"It's v, b, b, h, u, r, i, 1920, at gmail dot com."

Jenny"Let me confirm — v as in Victor, b as in bravo, b as in bravo — is that right?"

Caller"No — the b's are not b's, they should be d, as in dog."

Jenny"Got it — d as in dog, d as in dog. Is that correct?"

···

Jenny"I've created a support ticket for you. The ticket ID is C-B dash F-7-7-A-C-4-A-C."

Recording — actual call, 4:18

Recorded live through the deployed assistant, not staged.

07 / 9

What this actually costs to run

$0.09 /min minimum

Vapi's own floor rate, confirmed on our account's billing dashboard. Scales up from there with model and voice choice.

<$0.001 /call

Our AWS backend — Lambda and DynamoDB, both pay-per-request, no idle cost. Email goes out through Resend. Fractions of a cent per call at this volume.

08 / 9

Call flow

What happens on the call

The flow below is the "what." Every box on it was also a choice with a reason behind it — the cards under the diagram are the "why," for the six that weren't obvious.

Fixed greeting Listen + silentcaller-ID lookup De-escalate AI disclosure Reiterate · clarify ·confirm Identify category1 of 8 researched types Documented procedurewalk steps, one at a time No documented fixsay so honestly Still unresolved? → offer ticket Email →read back, one-time code sent Code verified →ticket + confirmation email Fails twice →mailing-address fallback has one has none mismatch / repeated failure
Category identification branches into "walk the steps" or "say so honestly" — both can lead to the ticket flow below.

Why raise startSpeakingPlan.waitSeconds to 1.0?

Default 0.4s cut callers off mid-sentence in live testing. Paired it with transcriptionEndpointingPlan: {onPunctuationSeconds: 0.2, onNoPunctuationSeconds: 2, onNumberSeconds: 0.5} so a finished sentence still triggers a fast turn — the delay only kicks in on genuine silence.

Why stopSpeakingPlan.numWords: 0?

numWords: 0 + voiceSeconds: 0.1 means any detected speech barges in immediately, no minimum-word buffer. Someone panicking about fraud doesn't finish a polite sentence before interrupting.

Why does the greeting land one turn late?

firstMessageMode: assistant-speaks-first fires before the tool-call pipeline attaches to the session — confirmed via a live GET /call/{id} log showing lookup_customer silently never firing on turn 0. Static firstMessage string now; the lookup runs on the model's first generated turn instead.

Why a code, not an identity check?

Coinbase's real verification is a government ID in-app — nothing phone-based to imitate. The OTP session is keyed by Vapi's call.id in DynamoDB with expires_at as a native TTL attribute; it confirms reachability only, for 5 minutes, then it's gone.

Why revert away from a "nicer" voice?

ElevenLabs (Lily → Brittney) measured ~9s of dead air per turn — likely TTS-queue latency on a shared, non-dedicated provider key. voice: {provider: "vapi", voiceId: "Emma"/"Sid", speed: 0.93} keeps first-audio-byte latency in-house.

Why drop phone_number from the create_ticket schema?

It was a field on the tool schema and the DynamoDB item, read by nothing downstream — send_verification_code/verify_code only ever touch email. Removed via PATCH /tool/{id}, the prompt, and the Lambda handler in one pass.

09 / 9

Architecture

Software components

Three plain, boring AWS pieces, plus Resend for email — chosen because each one earned its place, not because it's what everyone reaches for. The reasoning is below the diagram.

AWS Cloud Caller Vapi STT → LLM → TTS +1 213-699-1138 API Gateway HttpApi (v2), POST Lambda Python 3.12 128MB · 10s timeout DynamoDB on-demand + TTL Resend HTTPS API plain web request, no special access
A caller only ever talks to Vapi. Everything else — checking who's calling, sending a code, saving a ticket — happens through one small program, a database, and an email sender. No banking or account systems are anywhere in this path.

Why these specific AWS primitives?

One SAM template, four AWS::Serverless::* resources: an HttpApi event source (API Gateway v2), one AWS::Serverless::Function (Python 3.12, 128MB, 10s timeout), two AWS::DynamoDB::Table (PAY_PER_REQUEST), and the Resend API key as a NoEcho parameter — email goes out over Resend's HTTPS API. No custom runtime, no self-managed queue.

Why one Lambda, not four?

A single app.lambda_handler dispatches on event["rawPath"] — Vapi's toolCallList webhook shape on /tool-call, a plain JSON body on /register-customer — instead of four near-identical functions behind four routes needing the same fix each time.

Why DynamoDB only for OTP sessions and tickets?

jenny-otp-sessions keys on Vapi's call.id, with expires_at as a native TTL attribute — the one piece of state that has to survive two separate Lambda invocations in the same call (send → verify). Category walks and lookups stay stateless, single-invocation reads via DynamoDBCrudPolicy-scoped access.

Why Deepgram nova-3 with keyterm boosting?

A caller's email kept mistranscribing even after correction. Reading the raw STT output in CloudWatch — not just the model's replies — isolated the failure to the listening step. Swapped in nova-3 with a keyterm list (gmail.com, ACH, ACATS, Coinbase, …) to bias recognition toward domain vocabulary.

Why CORS-enable the HTTP API?

The /register-customer route needs a browser fetch() from a real page — Claude Artifacts block arbitrary cross-origin requests by CSP, so the page can't live there. SAM's Globals: HttpApi: CorsConfiguration handles the OPTIONS preflight and response headers with zero Lambda-side code.

"Vapi," "coinbase," and "Gmail" wordmarks in this deck are unofficial text treatments in each company's published brand colors — not their registered logos. The email mockup on the fraud demo slide is a recreated layout, not a screenshot. On the architecture slide, the Vapi, AWS and Resend logos are their owners' trademarks, shown only to identify the tools used.