Skip to main content
Allan Buntoengsuk

Fixing a $9M fraud loophole in DoorDash’s retail delivery system.

DoorDash

Year
2025
Role
Senior Product Designer
Tags
FraudMarketplaceMobileSystems DesignCross-functional

DoorDash's Shop and Deliver (DSD) orders lets Dashers purchase grocery and retail items on a DoorDash Red Card. The card is pre-loaded with the purchase amount + a small buffer.

We saw a fraud vector emerging: Dashers would complete the purchase, call support to unassign the order, and keep the items. We called it Swipe and Unassign. Customers wouldn’t get their items until way later and DoorDash had to absorb the cost.

Thousands of customers were affected every week and growing. Swipe and unassign’s annual cost to DoorDash was over $9M.

I owned end-to-end design for the response—building the first in-app return flow for DSD orders. This involved designing support and app flows, logic modeling, and getting alignment across six teams: Dasher/Logistics, DSD/New Verticals, Support, Legal, Ops, and Engineering. The system had to be enforceable, fair, and legally compliant.

The item return flow once a dasher gets to the store

Strategic Frame

DSD had a problem—there was no in-app way to enable a Dasher to return purchased items.

Without an in-app return mechanism, enforcement was only reactive—we would email the Dasher after the fact with instructions to return the item(s), hoping that would be enough to spur returns. Increasingly, we saw that it did not.

It was difficult enough time to figure out the return flow, but on top of that I had to balance designing a solution that sets clear expectations upfront, leaves room for legitimate edge cases and makes enforcement possible without seeming heavy-handed.

The Core Constraint

We couldn't force Dashers to return immediately. We also couldn’t legally end their dash early.

Two constraints killed obvious solutions.

  1. The system couldn’t interrupt an active shift.
  2. Operations said we couldn't end a dash early as that would create payout issues—the pay logic differs between EPO (Earn Per Offer) and EBT (Earn By Time) modes. The solution has to hold up whether a Dasher was on-dash or off.

I landed on a binary framework: Return Now or Return Later. Two different paths to the same return outcome, designed to address all constraints at once.

Return Now vs. Later diagram
  • Return Now keeps the dash running—we queue the return up next and hold all other offers until the return is made.
  • Return Later closes the dasher’s shift, giving them three days to fulfill the return, with their account in a suspension state until complete. This way a dasher is able to address a legitimate emergency they may have before doing the return. This was a fair path for honest Dashers, while also having actual consequences for bad actors.
When return later is selected, I dictated that the dasher would be in a suspended state with limited account access

However, Return Later needed something that didn't exist: a state that holds an account short of deactivation, with a defined exit condition. I designed it as a general suspension state rather than a return-specific screen, mostly because the return-specific version would have meant similar work with less ability to be reused by other teams.

The Design

The return prompt

When the store is closed, dashers see the screen to the right

An edge case that required extra consideration with engineering and the retail and grocery team: stores that are closing soon or already closed. I worked with the retail and grocery team to come up with a calculation to handle stores near closing time.

If the store is closed/will be closing, we surface Return Later as the only path, with the next open hours shown to aid a Dasher in planning.

The return flow

Full return flow (navigating to store, returning at store and conclusion)

Working with the Dasher & Logistics team, I mapped out the existing dropoff flow and adapted the Step Flow pattern from there: navigate to store, show receipt barcode, capture return receipt, add notes.

As an escape hatch, I also added a 'Can't complete return' action into each step for cases where the store won't take items back—be it because there are perishables, store policy, etc.

Left is regular state, right is pending exemption review

When an exemption request is pending, the fixed bottom CTA disappears. We still want the Dasher to be able to accomplish a return even when an exemption is pending. Removing the “Can’t complete return” CTA in this instance prevents Dashers from stacking exemption requests or deferring indefinitely, closing a loop in the system.

EPO vs. EBT parity

Pay structures differ between EPO and EBT modes, so both return states need to surface the right earnings and payout information for each. Dashers see accurate return payout details regardless of how they earn, informing them that they get paid half-pay for their incomplete delivery and the other half when they finish the return.

Return Now EPO/EBT (left) vs. Return Later EPO/EBT (right)

Alignment

Six teams had a say: Legal set the boundary on interrupting an active shift. Ops set it on payout logic across dash modes. New Verticals owned store hours and merchant behavior. Dasher/Logistics owned the delivery flow the return had to borrow from. Support owned the unassignment gate. Engineering owned what was buildable in the window. I needed to coordinate with all parties to ensure this was doable.

I saw an opportunity to make Support a deliberate design gate. Dashers can't self-unassign after swiping the Red Card; we made it so a Dasher would have to go through a live agent first.

I worked with Ops to ensure every agent was delivering the same message Dashers were seeing in-app: that unassigning requires a return. That made Support a mechanism for enforcement, on top of being a channel for communication.

Adding language to support screens and working with support ops to have them inform dashers that unassigning requires a return

Impact

Shipped to a partial rollout in late 2025.

This is the first-ever return flow for DSD. The Return Now / Return Later framework is now a reusable pattern. And because the return infrastructure now exists in-app, we are better equipped to tie enforcement (contract violations, deactivation) to actual return behavior, allowing us to take the appropriate actions.

The Return Later state turned out to be more general than the problem it was built for. It was adopted into the platform's deactivation guidance as the standard pattern for suspending an account with a path back, which means it now covers cases that have nothing to do with returns.

This design also anticipates batched return work in the future.

Reflection

Two things I flagged rather than solved.

The enforcement gate runs through Support agents, which means that agent messaging needs to stay consistent. I could design what the Dasher sees and what the agent is supposed to say, but not the training or QA that keeps those two aligned a year from now. I raised it as a standing dependency instead of absorbing it into design scope.

The exemption path is similar—I designed how a Dasher requests one and how the interface behaves while an exemption request is pending. Who adjudicates it, against what criteria, and how quickly, would sit with Ops. A return system with a slow exemption queue would be different from what I designed.

The challenge was navigating the breadth of the surfaces and teams involved. Fraud and integrity work runs horizontally across teams that own their surfaces vertically, so I’m often arriving with a problem someone else has to absorb into their roadmap.

What makes conversation possible is getting everyone on the same page early and constructing a framework that accounts for each constraint, instead of routing around any one of them.