DoorDash Has Seen Hundreds of AI-Agent Orders. Build a Checkout That Knows When to Stop A developer outlined a checkout state machine for AI shopping agents that enforces a deterministic boundary between an agent proposing an order and a merchant accepting one, blocking any direct transition from draft to submission. The design draws on DoorDash CEO Tony Xu's disclosure that third-party AI agents had placed "maybe several hundred orders in total" cumulatively, and on the Agent Payments Protocol (AP2) specification, which requires transaction validation in deterministic code rather than model prompts. A shopping agent can find a restaurant, assemble a cart, and call an ordering API. The hard question comes one step later: when is it allowed to spend the user's money? DoorDash's latest earnings discussion offers a useful reality check. CEO Tony Xu said the company had seen “maybe several hundred orders in total” from some third-party AI agents. That is a cumulative count for those agents, not all orders and not a quarterly total. The same report says customers still predominantly order through DoorDash's own app. The company has also built its own agent experiences and an MCP connector for corporate ordering. The signal is not that agents cannot order. It is that connecting an agent to a real fulfillment network does not automatically make people use it. TechCrunch reported Xu's remarks and context https://techcrunch.com/2026/10/30/doordash-said-its-only-received-several-hundred-orders-from-ai-agents/ . 1 The SEC-filed transcript of DoorDash's Q3 earnings call https://www.sec.gov/Archives/edgar/data/1792789/000114036126041195/ef20084600 425.htm records Xu's cumulative figure and describes its broader strategy around digital assistants and physical fulfillment. 2 For developers, the practical lesson is smaller and more actionable: do not let a language model turn a suggestion into an irreversible purchase. Build a deterministic boundary between “the agent found an option” and “the merchant accepted an order.” This tutorial develops that boundary as a small checkout state machine. It is a teaching example, not a production payment integration. A conversation is a poor source of authority. “Get the usual, but cheaper” is not a payment authorization. It leaves open which items, substitutions, delivery address, tip, fees, and final amount the user accepted. The agent can help interpret intent and propose a basket. The application should then turn that proposal into a structured quote from the merchant. The quote is the object the user reviews. It should include exact line items, quantities, merchant, address, total, currency, and an expiration time. If inventory or price changes, create a new quote and require a new decision rather than silently editing the old one. This is not merely a prudent UI convention. The Agent Payments Protocol AP2 specification https://ap2-protocol.org/ap2/specification/ separates the shopping agent, merchant, credential provider, payment processor, and a trusted surface for user consent. It says transaction validation must happen in deterministic code. Its direct flow has a person approve the closed checkout and payment, while its autonomous flow uses user-approved constraints that the completed checkout must satisfy. Those are different authorization modes, not interchangeable versions of a model prompt. 3 Start with explicit states: DRAFT : the agent is still assembling a proposed order. QUOTED : the merchant has returned a concrete, expiring quote. AWAITING APPROVAL : the user is shown that exact quote. APPROVED : the user approved the quote, and the approval is bound to its identifier and amount. SUBMITTING : the server is making one idempotent order request. CONFIRMED : the merchant accepted it and returned an order identifier. REJECTED , EXPIRED , or FAILED : a terminal result that cannot be mistaken for success. The key invariant is simple: no transition from DRAFT directly to SUBMITTING . The server checks the quote, the approval, and the merchant's current terms first. A model may request a transition, but it cannot grant itself the permission. Here is a TypeScript sketch of the policy check. It deliberately stops before payment processing. Production systems should use the merchant and payment provider's supported APIs rather than treating this function as a substitute for them. type Quote = { id: string; userId: string; merchantId: string; currency: string; totalMinor: number; expiresAt: number; items: Array<{ sku: string; quantity: number } ; }; type Approval = { quoteId: string; userId: string; approvedAt: number; maxTotalMinor: number; }; function canSubmit quote: Quote, approval: Approval | undefined, now: number, : boolean { if approval return false; if approval.userId == quote.userId return false; if approval.quoteId == quote.id return false; if now = quote.expiresAt return false; if quote.totalMinor approval.maxTotalMinor return false; if quote.items.length === 0 return false; return true; } Use integer minor units for money, such as cents, not floating-point dollars. The approval should refer to the immutable quote ID, not just “approved: true.” That makes a changed basket a different transaction. In a real service, the quote and approval records belong in durable storage with a transaction or compare-and-set transition so two workers cannot submit the same order concurrently. Networks fail at awkward moments. Your server may send an order request, the merchant may accept it, and the response may time out before your application receives it. Retrying with a new request can create a duplicate dinner order. Generate an idempotency key from the approved quote and persist it before contacting the merchant. Reuse that same key for every retry of the same logical submission. Record the request state, merchant response, and returned order ID. If the provider does not support idempotency, use its documented lookup or reconciliation mechanism before retrying. Do not invent a new order just because the first response was lost. The state transition should be guarded server-side, roughly like this: js async function submitApprovedQuote quoteId: string, userId: string { const attempt = await db.transaction async tx = { const order = await tx.orders.lockByQuoteId quoteId ; if order || order.userId == userId throw new Error "not found" ; if order.status === "CONFIRMED" return { existing: order }; if order.status == "APPROVED" throw new Error "not approved" ; if order.expiresAt <= Date.now throw new Error "quote expired" ; return tx.orders.markSubmitting order.id, order.idempotencyKey ; } ; if "existing" in attempt return attempt.existing; return merchantApi.createOrder attempt.payload, { idempotencyKey: attempt.idempotencyKey, } ; } This snippet assumes a transaction, row lock, and merchant API behavior that your actual stack must implement and test. It is not enough to put an idempotency header in a request if your application forgets which key belongs to which approved quote. A confirmation screen is not meaningful if it hides the details that could change the decision. Show the merchant, exact items and substitutions, delivery destination, fees, tax, tip, total, and the deadline for the quote. Make the action label explicit: “Place this order for $X” is clearer than “Continue.” If the amount rises, an item is substituted, or the address changes, return to approval. The authorization must also have a scope. “Spend up to $40 at this merchant for these listed items before 7:15 PM” is narrower than “buy groceries for me.” The AP2 specification https://ap2-protocol.org/ap2/specification describes open mandates for autonomous purchases, where a user approves constraints and the agent produces a specific checkout that is evaluated against them. It also recommends short expirations and requires that an agent not reuse an open mandate for another checkout until the previous one is resolved. That is a useful design pattern even if your implementation does not adopt AP2: bind permission to limits, merchant, duration, and the transaction being made. 3 Payment credentials need similar boundaries. Stripe's agentic commerce guide https://stripe.com/guides/agentic-commerce-primer describes Shared Payment Tokens scoped to a retailer, order amount, and time window, so an agent can initiate a payment without seeing the underlying payment details. That is a vendor-specific product description, not a general guarantee or a drop-in integration. The general principle is to avoid exposing reusable credentials to a model or agent process. 4 The agent's cart is a proposal. The merchant remains the source of truth for inventory, current price, taxes, discounts, fulfillment availability, and order acceptance. Revalidate the quote at the commit boundary. If the merchant returns a changed total, do not silently charge the difference. Move the order back to a state where the user can review the new terms. This also gives the system a clean failure vocabulary. “Agent suggested a basket,” “merchant returned a quote,” “user approved,” “payment authorized,” and “merchant confirmed” are separate events. Do not display “Your order is placed” after only a tool call or payment authorization. Wait for the authoritative confirmation and show the order ID or a clear pending status. PENDING RECONCILIATION , not a false success or a blind second order. These tests target the boundary between probabilistic planning and deterministic execution. They do not prove the whole checkout is safe, but they make the most consequential transitions explicit and reviewable. Use a human-present confirmation when the order is new, high value, sensitive, or likely to involve substitutions. Consider bounded autonomous purchasing only when the user has explicitly configured a narrow policy, the merchant provides stable structured quotes, credentials are scoped, and you can reconcile uncertain outcomes. Keep the two paths separate in both code and audit records. DoorDash's “several hundred” figure is not a verdict on agentic commerce. It is a reminder that a demo, an integration, and a habitual customer behavior are three different milestones. A useful system has to do more than call tools. It has to earn permission, preserve the exact terms that were approved, and recover safely when the network does something ordinary and inconvenient. Checkout review checklist: I write about developer tools, backend systems, and AI engineering. Subscribe if you want more practical pieces like this. Have you built an agent flow that can spend money or submit a real order? Where do you put the approval boundary? 1 TechCrunch: DoorDash said it’s only received “several hundred” orders from AI agents https://techcrunch.com/2026/10/30/doordash-said-its-only-received-several-hundred-orders-from-ai-agents 2 DoorDash Q3 earnings-call transcript, filed with the SEC https://www.sec.gov/Archives/edgar/data/1792789/000114036126041195/ef20084600 425.htm 3 Agent Payments Protocol specification https://ap2-protocol.org/ap2/specification 4 Stripe: Agentic Commerce, A Getting Started Guide https://stripe.com/guides/agentic-commerce-primer