Build Two Interacting Services That Carry Out a Realistic Refund Flow

Read the full interview experience this question came from →

Quick Overview

A senior coding exercise, with an AI assistant allowed, to build two cooperating services that carry out a refund end to end. It tests service boundaries, a refund state machine, idempotent retries, handling of declines and timeouts, and a runnable simulation of realistic refund scenarios.

Build Two Interacting Services That Carry Out a Realistic Refund Flow

Company: DoorDash

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Onsite

Implement a refund flow as **two services that interact with each other** to complete a refund. This is an AI-assisted coding round: an AI coding assistant is available in the editor. The code should simulate a realistic refund scenario rather than a single function that flips an order's status to "refunded". The main signal is whether you have thought through the architecture of the whole flow before generating code. The assistant is there to speed up typing, not to make the design decisions. Interviewers for this exercise differ in which aspects they emphasize, so expect probing in areas you did not raise yourself. The report does not fix how responsibilities are split between the two services, what interface connects them, or how state is stored, so settling those choices explicitly is part of the task. Unless the interviewer asks for real network servers, model each service as an in-process component whose method calls stand in for remote calls. ### Clarifying Questions - Which two services should exist, and which one owns the refund record? For example, an order-side service that decides whether a refund is allowed and a payment-side service that moves the money. - Are partial refunds allowed, and can one order receive several refunds as long as their total stays within what was paid? - Should the call between the services be a synchronous request and response, or asynchronous through a queue or events? - Which failures should the simulation demonstrate: the payment side declining, a request that never arrives, or a request that succeeds while its response is lost? - Is persistence required, or is in-memory state acceptable for the round? ### Part 1 — Service boundaries and the refund lifecycle Define the two services: what state each one owns, which operations each exposes to the other, and the states a refund moves through from request to final outcome. ```hint Follow the money Decide which service is the source of truth for how much of an order can still be refunded, and which one is the only component allowed to move money. The interface between them follows from that split. ``` #### What This Part Should Cover - A clear ownership split in which no piece of state is written by both services. - An explicit refund state machine, including a state for an outcome that is not yet known. - The request and response contract between the services, including an identifier that lets a retried request be recognized. ### Part 2 — Implement the interaction Implement both services and a small driver that runs realistic scenarios end to end: a successful refund, a request that must be rejected, and at least one failure in the call between the services. ```hint Make the retry safe Assume any call from one service to the other can fail after the other side has already done the work. Decide what the caller does next, and what the callee does when the same request arrives twice. ``` #### Clarifying Questions for this Part - When the payment side times out, should the refund be shown to the customer as failed, as pending, or be retried transparently? - Must two concurrent refund requests for the same order be handled safely? #### What This Part Should Cover - Validation before any money moves: the order exists, the amount is positive, and the total refunded stays within the amount paid. - Idempotent handling of duplicate and retried requests on both sides of the call. - Correct final states after a decline, a request that never arrived, and a lost response. - A runnable driver whose scenarios demonstrate those behaviors. ### What a Strong Answer Covers - Architecture settled and explained before code generation, with the assistant's output reviewed rather than accepted as generated. - Correct money handling: integer minor units, no double refunds, and totals that agree across the two services. - Business rules kept separate from the simulated transport, so failures can be injected in tests. - A clear account of what the simulation leaves out compared with production, such as durable storage, a message queue and reconciliation. ### Follow-up Questions - How would the design change if the payment side confirmed refunds later through a callback or event instead of in its response? - How would you detect and repair a refund whose outcome stays unknown because every retry also timed out? - If refunds above some amount, or for certain reasons, needed manual approval, where would that rule live and how would the state machine change? - How would you test the two services together without a real payment processor?

Overview: A senior coding exercise, with an AI assistant allowed, to build two cooperating services that carry out a refund end to end. It tests service boundaries, a refund state machine, idempotent retries, handling of declines and timeouts, and a runnable simulation of realistic refund scenarios.

Read the full DoorDash Software Engineer interview experience this question came from

|Home/Software Engineering Fundamentals/DoorDash
DoorDash logo
DoorDash
Sep 10, 2026
mediumSoftware EngineerOnsiteSoftware Engineering Fundamentals
0
0

Implement a refund flow as two services that interact with each other to complete a refund. This is an AI-assisted coding round: an AI coding assistant is available in the editor. The code should simulate a realistic refund scenario rather than a single function that flips an order's status to "refunded".

The main signal is whether you have thought through the architecture of the whole flow before generating code. The assistant is there to speed up typing, not to make the design decisions. Interviewers for this exercise differ in which aspects they emphasize, so expect probing in areas you did not raise yourself.

The report does not fix how responsibilities are split between the two services, what interface connects them, or how state is stored, so settling those choices explicitly is part of the task. Unless the interviewer asks for real network servers, model each service as an in-process component whose method calls stand in for remote calls.

Clarifying Questions Guidance

  • Which two services should exist, and which one owns the refund record? For example, an order-side service that decides whether a refund is allowed and a payment-side service that moves the money.
  • Are partial refunds allowed, and can one order receive several refunds as long as their total stays within what was paid?
  • Should the call between the services be a synchronous request and response, or asynchronous through a queue or events?
  • Which failures should the simulation demonstrate: the payment side declining, a request that never arrives, or a request that succeeds while its response is lost?
  • Is persistence required, or is in-memory state acceptable for the round?

Part 1 — Service boundaries and the refund lifecycle

Define the two services: what state each one owns, which operations each exposes to the other, and the states a refund moves through from request to final outcome.

What This Part Should Cover Guidance

  • A clear ownership split in which no piece of state is written by both services.
  • An explicit refund state machine, including a state for an outcome that is not yet known.
  • The request and response contract between the services, including an identifier that lets a retried request be recognized.

Part 2 — Implement the interaction

Implement both services and a small driver that runs realistic scenarios end to end: a successful refund, a request that must be rejected, and at least one failure in the call between the services.

Clarifying Questions for this Part Guidance

  • When the payment side times out, should the refund be shown to the customer as failed, as pending, or be retried transparently?
  • Must two concurrent refund requests for the same order be handled safely?

What This Part Should Cover Guidance

  • Validation before any money moves: the order exists, the amount is positive, and the total refunded stays within the amount paid.
  • Idempotent handling of duplicate and retried requests on both sides of the call.
  • Correct final states after a decline, a request that never arrived, and a lost response.
  • A runnable driver whose scenarios demonstrate those behaviors.

What a Strong Answer Covers Guidance

  • Architecture settled and explained before code generation, with the assistant's output reviewed rather than accepted as generated.
  • Correct money handling: integer minor units, no double refunds, and totals that agree across the two services.
  • Business rules kept separate from the simulated transport, so failures can be injected in tests.
  • A clear account of what the simulation leaves out compared with production, such as durable storage, a message queue and reconciliation.

Follow-up Questions Guidance

  • How would the design change if the payment side confirmed refunds later through a callback or event instead of in its response?
  • How would you detect and repair a refund whose outcome stays unknown because every retry also timed out?
  • If refunds above some amount, or for certain reasons, needed manual approval, where would that rule live and how would the state machine change?
  • How would you test the two services together without a real payment processor?
Loading comments...