Design game credit system with add/spend/refund APIs
Company: Ixl
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Technical Screen
## System Design Prompt: Game Credit System with Add, Spend, and Refund APIs
You are designing a backend service to manage **virtual game credits** for one or more video games.
Players can:
- **Add** credits to an account, such as after a purchase, promotion, or bonus.
- **Spend** credits, such as to buy an in-game item.
- **Refund** a previous spend when a purchase is cancelled, reversed, or failed.
Design the data model, APIs, and consistency strategy for this service.
### Constraints & Assumptions
- Credits are represented as integer units.
- Each player has one credit account per game or currency type unless you explicitly choose a different model.
- The service must keep balances correct under concurrent requests from multiple app servers.
- Clients may retry requests after timeouts, so duplicate processing must be prevented.
- A full financial ledger is not required, but the design should be auditable and reliable enough for an in-game economy.
- Assume REST over HTTP and a relational database unless you justify another storage choice.
### Clarifying Questions to Ask
- Are credits purchased with real money, earned in-game, promotional, or all of the above?
- Are there multiple games, regions, or currency types?
- Can a spend be partially refunded, or only fully refunded?
- Do credits expire, and are there restrictions on refunding promotional credits?
- What throughput and latency targets should the service support?
- Is strong consistency required globally, or only per player account?
### Part 1 - Data Model
Design tables or entities for accounts, balances, and credit transactions. Include key fields and relationships.
#### What This Part Should Cover
- An account or wallet table keyed by player, game, and currency.
- A transaction ledger table with type, amount, status, idempotency key, related transaction reference, timestamps, and metadata.
- Constraints that prevent duplicate idempotency keys and double refunds.
- A balance representation that is either derived from the ledger or stored as a cached account balance updated transactionally.
- Audit fields and status transitions for pending, committed, failed, and reversed operations.
### Part 2 - APIs
Specify APIs for add, spend, and refund. Include method, URL, request body, success response, and common error responses.
#### What This Part Should Cover
- `POST /v1/accounts/{accountId}/credits:add` or equivalent.
- `POST /v1/accounts/{accountId}/credits:spend` with insufficient-funds behavior.
- `POST /v1/transactions/{transactionId}:refund` or equivalent.
- Required fields such as amount, currency, reason, idempotency key, external reference, and metadata.
- Response fields such as transaction ID, account ID, new balance, status, and error code.
### Part 3 - Consistency, Idempotency, and Concurrency
Explain how you keep balances and transactions correct when multiple requests hit the same account concurrently or clients retry requests.
#### What This Part Should Cover
- Database transactions around balance update and ledger insert.
- Row-level locking or optimistic concurrency on the account row.
- Atomic conditional update for spends to prevent negative balances.
- Unique idempotency keys scoped to account and operation.
- Refund logic that locks or checks the original spend and prevents duplicate refunds.
- Failure handling for network timeouts, database failures, and partial writes.
### Part 4 - Scale and Reliability
Describe how the design evolves for high traffic and what can fail.
#### What This Part Should Cover
- Stateless application servers behind a load balancer.
- Database indexes and sharding or partitioning by account ID if volume grows.
- Hot-account handling, queues only where they do not weaken correctness, and reconciliation jobs.
- Outbox or event stream for downstream analytics, inventory, notifications, and fraud checks.
- Monitoring for balance mismatches, duplicate-key errors, failed refunds, latency, and error rates.
### What a Strong Answer Covers
A strong answer combines API clarity with transactional correctness. It should show how the ledger, balance, idempotency keys, and refund references work together to prevent double-spend, duplicate add, and double-refund bugs under retries and concurrency.
### Follow-up Questions
- Would you compute balance from the ledger or store it in the account row?
- How would you support multiple currencies or games?
- How would you process a payment callback that adds credits exactly once?
- How would you handle partial refunds?
- How would you audit and repair a balance mismatch?
- What changes if the game needs 50,000 credit operations per second?
Quick Answer: Practice designing a game credit wallet service with add, spend, and refund APIs backed by a transactional ledger. The solution covers schema design, REST request and response formats, idempotency keys, row-level locking, conditional spends, refund references, failure handling, reconciliation, and scaling for high-volume game economies.