Skip to main content
Allan Buntoengsuk

DoorDash

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

Year
2025
Role
Senior Product Designer
Tags
FraudMarketplaceMobileSystems DesignCross-functional

DoorDash's Dasher 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 pattern emerging: Dashers would complete the purchase, call support to unassign the order, and keep the items. Consumers got nothing and DoorDash had to absorb the cost.

Thousands of consumers were affected every week, and growing. The annual cost to DoorDash was over $9M.

I owned end-to-end design for the response—building the first return flow ever for DSD orders. This involved 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 reactive—we would flag it after the fact and hope it deterred repeat behavior. Increasingly, we saw that it did not.

It was difficult enough to figure out the return flow—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 and we legally can’t 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.

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

Return Now vs. Later diagram
  • Return Now keeps the dash running—we queue the return up next, with all other offers held until it's done.
  • Return Later closes the dasher’s shift, giving them three days to return, with their account in a suspension state until complete. This way a dasher is able to address any legitimate emergency they may have before facilitating the return. A fair path for honest Dashers, actual consequences for bad actors, and it works across every dash mode and state.
When return later is selected, I dictated that the dasher would be in a suspended state with limited account access

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 been the same work with a narrower ceiling.

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 so a Dasher isn't left guessing.

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 or whatever the reason.

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 an obvious 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 execute the return.

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

Alignment

Six teams had a say and everyone wanted to be heard. 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 find a shape that fit all six at once.

Support became a deliberate design gate. Dashers can't self-unassign after swiping the Red Card; they have to go through an agent first.

I worked with Ops to ensure every agent was delivering the same message Dashers were seeing in-app: unassigning requires a return. The unassign action itself is gated by a human. 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 return flow DSD has ever had. The Return Now / Return Later framework is now a reusable pattern. And because the return infrastructure exists in-app for the first time, 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 it holds only as long as agent messaging stays consistent. I could design what the Dasher sees and what the agent is supposed to say. I could not design the training or the 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 has a similar story—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, sat with Ops. A return system with a slow exemption queue is a different system than the one I designed.

The challenge throughout was navigating the breadth of the surfaces and teams involved. Fraud and integrity work runs horizontally across teams that own their surfaces vertically, so most of the job is arriving with a problem someone else now has to absorb into their roadmap.

What made the conversation possible was getting everyone on the same page early and constructing a framework that accounted for each constraint, rather than routing around any one of them.