← Blog

How to Build an AI Agent That Orders from DoorDash

Letting an AI agent place a real DoorDash order is two separate engineering problems wearing one trench coat. The first is driving the store: acting as a signed-in shopper, finding a restaurant, building a cart, and submitting an order against a site that does not want to be automated. The second is paying safely: moving real money with limits, confirmation, and the ability to undo a half-finished charge. This post covers the first half. The companion post, how AI agents pay for DoorDash orders safely, covers the second.

If you would rather not build any of it: Agentcard ships this as an MCP server your users connect to over OAuth, and a single buy tool that runs the whole flow. The payment side is solved for you entirely. The rest of this guide is for the engineers who want to understand what that actually takes.

The shape of the problem

DoorDash has no public ordering API for third parties, it is a marketplace with thousands of stores rather than a single catalog, and it is defended against automation. Any agent that checks out for a user has to solve four things in order: prove it is an authorized shopper, find the right store, build a cart the merchant will accept, and place the order. Get the order half right and the payment half is still ahead of you.

Identity: the agent has to be a signed-in shopper

You cannot place a DoorDash order anonymously, and creating throwaway accounts at scale does not survive contact with a bot-defended marketplace. The reliable pattern is to borrow the user's own logged-in session. The user signs in once through a hosted or extension-driven browser, you capture the resulting session, and every later request rides on it.

Session vaulting: the captured session is a credential, so treat it like one. Encrypt it at rest (AES-256-GCM is a sensible default) and scope it tightly — to the user, the connecting application, and the merchant. That last point matters most when you are a platform serving many apps: one app's link must never be readable by another. Scope every read and write by the connection identity so a user's grocery agent and their travel agent cannot see each other's sessions.

Sessions expire. Build for it: detect the expired-session signal, surface a clean "reconnect your DoorDash account" prompt, and never treat a stale session as a hard failure.

The anti-bot reality

This is the part most build-it-yourself plans underestimate. A marketplace like DoorDash inspects far more than your cookies. It fingerprints the network client itself — the TLS handshake, the ordering of headers, the shape of the connection — so a plain server-side HTTP client gets flagged before it sends a single useful request, no matter how perfect your cookies are.

The practical consequence: requests have to originate from a client that genuinely resembles a real browser at the network layer, and the techniques for staying resemblant are a moving target that shifts whenever the other side updates its defenses. This is an ongoing operational cost, not a one-time integration. We are deliberately not publishing the specifics here; the honest takeaway for anyone scoping this work is that the anti-bot arms race, not the cart logic, is what makes a DoorDash agent expensive to keep alive.

Driving a multi-store marketplace

Because DoorDash is a marketplace, "search" happens twice. First the agent finds a store near the delivery address, then it searches for items inside that store. A clean flow looks like this:

  • Search stores by query and delivery location, returning a short list with names and addresses.
  • Select a store, which scopes every subsequent item search and cart action to it.
  • Search items within the selected store, returning normalized products with stable IDs and prices in minor units (cents).
  • Mutate the cart — add, set quantity, remove, clear — and read back the merchant's authoritative totals, including fees, tax, and delivery.

The merchant returns its own raw shapes. Your job is to normalize them into one internal model so the rest of your system never has to know which store it is talking to.

The store-adapter pattern

The single most useful design decision is to put every merchant behind one interface. Your orchestration layer talks to the interface; a per-merchant adapter handles that store's quirks, session, and response shapes. Adding a new merchant becomes "write one adapter," not "rewrite the agent."

interface StoreAdapter {
  // identity
  link(session: CapturedSession): Promise<LinkResult>

  // discovery (marketplaces implement the store methods too)
  searchStores?(query: string, location: GeoPoint): Promise<Store[]>
  selectStore?(storeId: string): Promise<void>
  searchItems(query: string): Promise<Product[]>

  // cart
  addToCart(productId: string, quantity: number): Promise<Cart>
  viewCart(): Promise<Cart>
  setQuantity(productId: string, quantity: number): Promise<Cart>

  // checkout (covered in the payments post)
  prepareCheckout(amountCents: number, card: MintedCard): Promise<CheckoutPrep>
  placeOrder(opts: { tipCents?: number; deliveryTime?: string }): Promise<PlaceResult>
}

A DoorDashAdapter implements all of it; a cooperative grocery store implements a simpler subset (no searchStores). The orchestration layer above never changes. This is the same pattern we use in production, and it is what lets one buy tool span very different merchants — see how an agent shops and checks out for the user-facing side of it.

Placing the order

With a cart assembled and a store selected, an order needs a delivery address, an optional tip, and a delivery time. Two details trip people up. Tips should be passed explicitly in minor units rather than inferred. And delivery time, when it is not "as soon as possible," must be an absolute instant with an explicit time zone — never a naive local time, which silently reinterprets itself and books the wrong window.

Critically, placing the order is where the order half hands off to the payment half. You do not actually submit until a funded card exists and the user has confirmed. That handoff, and everything that can go wrong during it, is the subject of the payments and safety post.

What breaks in production

  • Session expiry. The most common failure. Refresh on the expired-session signal and prompt the user to reconnect rather than erroring out.
  • Anti-bot drift. Defenses change without notice. Treat keeping the client browser-like as ongoing maintenance, not a finished task.
  • Response-shape drift. The merchant changes its payloads on its own schedule. Normalize aggressively and fail loudly when a field you depend on disappears.
  • Rate limits. Back off with jitter on throttling responses; aggressive retries make the bot detection worse, not better.

How does an AI agent order from DoorDash without getting blocked?

It rides on the user's own captured, signed-in session and issues requests from a client that resembles a real browser at the network layer, not a bare HTTP client. The cart and order calls are the easy part; staying unblocked is the hard, ongoing part, because marketplaces fingerprint the network client itself and update those defenses continually.

What is the store-adapter pattern for agent checkout?

It is an interface that hides every merchant's specifics behind common methods — search, cart, checkout — so your agent orchestration stays merchant-agnostic. Each supported store ships its own adapter implementation. Adding DoorDash, a grocer, or a travel site means writing one adapter, not changing the agent.

Can an AI agent search across multiple DoorDash stores?

Yes. DoorDash is a marketplace, so the flow is two-stage: search stores near the delivery address, select one, then search items within it. An agent can enumerate nearby stores carrying an item and pick on price, rating, or delivery time before it ever builds a cart.

Or skip the build: connect Agentcard

Everything above — session capture and vaulting, the anti-bot maintenance, multi-store search, the adapter, the order mechanics — is real, ongoing engineering. If you are an agent platform that wants to give users DoorDash ordering without owning that work, Agentcard exposes it as an MCP server your users authenticate to over OAuth. Your agent calls one conversational buy tool ("order a Caesar salad from Zuni on DoorDash") and the whole flow runs server-side. And you never solve the payment part: virtual card issuance, tokenization, spend limits, settlement, and refunds are all handled for you.

The Model Context Protocol is the open standard that makes this a drop-in for any compliant agent; see the MCP specification for how tools are exposed.

Next steps