We were developing a workflow to ensure the customer has a seamless experience in completing a payment while in conversation with a Voice AI agent in a single call, without going anywhere else.
We found it to be achievable with Vapi, Twilio Pay, and Stripe.
During that implementation, we ran into an interesting problem.
The customer never reached the payment details stage, and the call hung up.
The original flow looked simple.
Customer calls a Twilio number, and it connects the call to a Vapi assistant using Media Streams. When the assistant decides payment is needed, the backend redirects the live Twilio call to “<Pay>”.
In theory, this should have worked. But it didn’t.
Twilio did fetch the payment TwiML, but because the live call was already inside a Vapi “<Connect><Stream>”, interrupting that stream caused the assistant/call flow to behave like the call was ending. Regardless of whether the payment IVR started or not, the call was immediately ended by Vapi.
The Fix
The fix was architectural.
Instead of letting Vapi own the customer call leg directly, Twilio became the call owner. The customer leg joins the Twilio Conference, and the Vapi leg also joins as an SIP participant in the same conference.
When a payment is to be completed, only the customer leg is redirected to Twilio Pay. Vapi remains parked in the conference. Once payment is completed, the customer leg returns to the same conference.
With this, we were able to achieve a seamless experience in which the customer can complete payment capture in a PCI-compliant way.