Ramp

Ramp Software Engineer Interview Questions

18+ questions from real Ramp Software Engineer interviews, reported by candidates.

18
Questions
6
Round Types
8
Topic Areas
2024-2026
Year Range

Round Types

Phone 6 OA 5 Technical 2 Onsite 2 System Design 1 Phone Screen 1

Top Topics

Questions

Hey guys, I have an interview coming up soon for Ramp and they mention "No leetcode-style or algorithmic type questions" but yet it's a coding round in my Programming Language of choice. I have two we

I have a 60-minute live coding interview coming up for the Ramp Android Software Engineer Internship and was curious if anyone here has gone through the process recently. From what I’ve seen online, i

This post was last edited by Anonymous on 2025-09-29 10:38. I applied for an Applied AI Engineer position at the end of September and immediately received an online assessment (OA) invitation. It was

This question has appeared before. This question bank is probably quite small. Given a set of flight information, each flight includes: departure airport, departure time, arrival airport, arrival time

This post was last edited by Anonymous on 2025-09-29 11:07. This is my third sharing this week. I'm asking for points to see my interview experience! This time, I applied for a Software Engineer/Platf

I think I got the online assessment (OA) for free by mass applying. Many people said they got 45 minutes, but mine was 90 minutes for the code signal 4 parts. It was progressive; you had to solve one

Design a feature flag system for a mid size company. It should support an API like flags.isOn(String flagName, Context context); Design everything needed to support this api, flag rollouts, ramp...

## Round 1 - Coding / OA ## Problem Simulate a bank account system. Implement `deposit`, `withdraw`, and `transfer`. Withdrawals fail if the account balance would fall below zero. Transfers atomically move funds between two accounts — if the source lacks funds, the transfer fails entirely. ```python class BankAccount: def __init__(self, account_id: str, balance: float): ... def deposit(self, amount: float) -> float: # returns new balance ... def withdraw(self, amount: float) -> float: # raises InsufficientFundsError if fails ... class Bank: def __init__(self): ... def add_account(self, account: BankAccount) -> None: ... def transfer(self, from_id: str, to_id: str, amount: float) -> bool: ... def get_balance(self, account_id: str) -> float: ... ``` ## Example ``` bank = Bank() bank.add_account(BankAccount("ACC1", 500)) bank.add_account(BankAccount("ACC2", 100)) bank.transfer("ACC1", "ACC2", 200) -> True bank.get_balance("ACC1") -> 300 bank.get_balance("ACC2") -> 300 bank.transfer("ACC2", "ACC1", 500) -> False # insufficient ``` ## Follow-ups 1. How do you prevent race conditions if two threads transfer from the same account simultaneously? 2. How would you implement a transaction history log with timestamps? 3. What happens if `from_id` or `to_id` doesn't exist in the bank? 4. How would you add an overdraft limit so accounts can go negative up to a set threshold?

## Problem Implement calendar operations such as event scheduling, conflict detection, or free time finding. ## Likely LeetCode equivalent No direct unambiguous match. ## Tags arrays, sorting, greedy

## Problem Render or compute a calendar view layout for a set of events, handling overlaps and display constraints. ## Likely LeetCode equivalent No direct match with high confidence. ## Tags arrays, sorting, coding_other

## Round 1 - Coding ## Problem Given the contents of a CSV file as a string, implement a query engine that supports `SELECT`, `WHERE` (with `=` and `>` conditions), and `ORDER BY`. No external CSV or database libraries allowed. ```python class CSVQuery: def __init__(self, csv_data: str): ... def select(self, columns: list[str]) -> list[dict]: ... def where(self, column: str, op: str, value: str) -> 'CSVQuery': # op: "=", ">", "<" ... def order_by(self, column: str, ascending: bool = True) -> 'CSVQuery': ... def execute(self) -> list[dict]: ... ``` ## Example ``` csv = """name,age,dept Alice,30,Eng Bob,25,Sales Carol,35,Eng""" q = CSVQuery(csv) result = q.where("dept", "=", "Eng").order_by("age").select(["name","age"]).execute() # -> [{"name":"Alice","age":"30"},{"name":"Carol","age":"35"}] ``` ## Follow-ups 1. How do you handle quoted fields that contain commas, e.g. `"Smith, John"`? 2. How would you support numeric comparison for integer and float columns? 3. Add support for `LIMIT N` — where in the chain does it apply? 4. How would you handle missing or empty values in a column used for sorting or filtering?

## Round 1 - Coding ## Problem Implement a command-line currency converter. The CLI accepts commands to set exchange rates, convert amounts, and query conversion chains (convert through an intermediate currency if a direct rate isn't available). ```python class CurrencyCLI: def set_rate(self, from_curr: str, to_curr: str, rate: float) -> None: ... def convert(self, amount: float, from_curr: str, to_curr: str) -> float: # returns -1.0 if conversion is impossible ... def best_rate(self, from_curr: str, to_curr: str) -> float: # returns the effective rate via the best available path ... ``` ## Example ``` cli = CurrencyCLI() cli.set_rate("USD", "EUR", 0.92) cli.set_rate("EUR", "GBP", 0.86) cli.convert(100, "USD", "EUR") -> 92.0 cli.convert(100, "USD", "GBP") -> 79.12 # USD->EUR->GBP cli.convert(100, "USD", "JPY") -> -1.0 # no path cli.best_rate("USD", "GBP") -> 0.7912 ``` ## Follow-ups 1. Rates are bidirectional — if USD->EUR is 0.92, what is EUR->USD? How do you store both? 2. How do you find the path that maximizes the converted amount (best rate) rather than any valid path? 3. How do you detect arbitrage opportunities (a cycle where converting back yields more than you started)? 4. How would you cache rates with a TTL so stale rates expire after 60 seconds?

## Round 1 - Coding ## Problem Implement a flight tracking system. Flights have a status that updates over time. Support querying all flights by origin, destination, or status. Also return any flights currently delayed. ```python class FlightTracker: def add_flight(self, flight_id: str, origin: str, dest: str, departure: str, arrival: str) -> None: ... def update_status(self, flight_id: str, status: str, delay_minutes: int = 0) -> None: # status: "on_time", "delayed", "landed", "cancelled" ... def get_delayed(self) -> list[str]: # returns flight_ids ... def flights_from(self, origin: str) -> list[dict]: ... def flights_to(self, dest: str) -> list[dict]: ... ``` ## Example ``` tracker = FlightTracker() tracker.add_flight("AA100", "JFK", "LAX", "08:00", "11:30") tracker.add_flight("UA200", "ORD", "LAX", "09:00", "12:00") tracker.update_status("AA100", "delayed", 45) tracker.get_delayed() -> ["AA100"] tracker.flights_to("LAX") -> [{"id":"AA100",...},{"id":"UA200",...}] ``` ## Follow-ups 1. How do you efficiently query all flights originating from a given airport if you have 10,000 flights? 2. If a flight status changes multiple times, how do you maintain a history of state transitions? 3. How would you alert subscribers when a specific flight's status changes? 4. Design the schema to store this in a relational database. Which columns would you index?

## Round 1 - Frontend ## Problem Build a reusable React `Autocomplete` component. As the user types, it fetches suggestions from an async source and renders a dropdown. Selecting a suggestion fills the input and clears the dropdown. ```jsx // Props interface interface AutocompleteProps { fetchSuggestions: (query: string) => Promise<string[]>; onSelect: (value: string) => void; placeholder?: string; debounceMs?: number; // default 300 } function Autocomplete(props: AutocompleteProps) { // Your implementation } ``` ## Example ``` <Autocomplete fetchSuggestions={(q) => api.search(q)} onSelect={(val) => console.log("Selected:", val)} placeholder="Search..." debounceMs={300} /> // User types "rea" -> debounce 300ms -> fetchSuggestions("rea") called // -> ["React", "Reabsorb", "Read"] dropdown appears // User clicks "React" -> input shows "React", dropdown closes, onSelect called ``` ## Follow-ups 1. How do you handle a race condition where a slow response from an earlier query arrives after a newer one? 2. How do you make the dropdown keyboard-navigable (arrow keys, Enter to select, Escape to close)? 3. How would you cache recent query results so repeated keystrokes don't re-fetch the same data? 4. How do you handle the case where `fetchSuggestions` throws an error?

## Round 1 - Coding ## Problem Implement a Rock Paper Scissors game engine. Support two players (human or bot), track wins/losses/draws per player, and return a match summary after `N` rounds. ```python class RPSGame: MOVES = {"rock", "paper", "scissors"} def __init__(self, rounds: int): ... def play_round(self, move1: str, move2: str) -> str: # returns "player1", "player2", or "draw" ... def get_stats(self) -> dict: # {"player1": {"wins":int,"losses":int,"draws":int}, # "player2": {...}, "rounds_played": int} ... def winner(self) -> str: # "player1", "player2", or "tie" after all rounds ... ``` ## Example ``` game = RPSGame(rounds=3) game.play_round("rock", "scissors") -> "player1" game.play_round("paper", "paper") -> "draw" game.play_round("scissors", "rock") -> "player2" game.get_stats() # -> {"player1":{"wins":1,"losses":1,"draws":1}, # "player2":{"wins":1,"losses":1,"draws":1}, "rounds_played":3} game.winner() -> "tie" ``` ## Follow-ups 1. How would you add Rock Paper Scissors Lizard Spock? What data structure best represents the win/loss matrix? 2. Implement a simple bot strategy: always play the move that beat the opponent's last move. 3. How do you validate that moves are legal and handle invalid input gracefully? 4. How would you serialize and restore game state mid-match?

## Round 1 - Coding / OA ## Problem Write a function that converts a snake_case string to camelCase and another that goes the reverse direction. Handle leading/trailing underscores and consecutive underscores gracefully. ```python def snake_to_camel(s: str) -> str: ... def camel_to_snake(s: str) -> str: ... ``` ## Example ``` snake_to_camel("hello_world") -> "helloWorld" snake_to_camel("get_user_by_id") -> "getUserById" snake_to_camel("__private_var__") -> "__privateVar__" snake_to_camel("already") -> "already" camel_to_snake("helloWorld") -> "hello_world" camel_to_snake("getUserById") -> "get_user_by_id" camel_to_snake("HTMLParser") -> "html_parser" camel_to_snake("myURLParser") -> "my_url_parser" ``` ## Follow-ups 1. How do you handle acronyms like `HTMLParser` or `URLEncoder` in camel-to-snake conversion? 2. Extend your solution to also support PascalCase as a third convention. 3. How would you apply these conversions recursively to all keys in a nested JSON object? 4. What edge cases arise with empty strings, single characters, or strings that are already in the target format?

## Round 1 - Coding ## Problem Implement a subscription tracking system. Users subscribe to plans with monthly prices. Mid-cycle plan changes are prorated. Compute the total bill for a user at the end of each month. ```python class SubscriptionTracker: def subscribe(self, user_id: str, plan: str, price_per_month: float, start_day: int) -> None: ... def change_plan(self, user_id: str, new_plan: str, new_price: float, change_day: int) -> None: ... def cancel(self, user_id: str, cancel_day: int) -> None: ... def monthly_bill(self, user_id: str, days_in_month: int) -> float: ... ``` ## Example ``` tracker = SubscriptionTracker() tracker.subscribe("u1", "basic", 30.0, start_day=1) tracker.monthly_bill("u1", days_in_month=30) -> 30.0 tracker.subscribe("u2", "basic", 30.0, start_day=1) tracker.change_plan("u2", "pro", 60.0, change_day=16) # Day 1-15: basic @ 30/30 * 15 = 15.00 # Day 16-30: pro @ 60/30 * 15 = 30.00 tracker.monthly_bill("u2", days_in_month=30) -> 45.0 ``` ## Follow-ups 1. How do you handle a user who cancels mid-month — do they get a refund or not? 2. How would you support annual subscriptions with monthly billing breakdowns? 3. What data structure tracks multiple plan changes within a single month? 4. How do you generate an invoice line-item breakdown instead of just the total?

## Round 1 - Coding ## Problem Given a block of text, compute the frequency distribution of word lengths. Return a sorted list of `(length, count)` pairs and render a simple ASCII histogram. ```python def word_length_distribution(text: str) -> list[tuple[int, int]]: # returns [(length, count), ...] sorted by length ascending ... def render_histogram(distribution: list[tuple[int, int]]) -> str: # each row: "length | ##### count" ... ``` ## Example ``` text = "the quick brown fox jumps over the lazy dog" word_length_distribution(text) # -> [(3,4),(4,2),(5,2),(6,1)] # "the"x2, "fox", "the" -> len 3 appears 4 times # "over","lazy" -> len 4 appears 2 times, etc. render_histogram([(3,4),(4,2),(5,2)]) # 3 | #### 4 # 4 | ## 2 # 5 | ## 2 ``` ## Follow-ups 1. What counts as a "word"? How do you handle punctuation attached to words like `"fox,"` or `"dog."`? 2. How would you normalize the histogram so bars represent percentages instead of raw counts? 3. How does the output change for very long words (length 20+) — does your histogram stay readable? 4. Extend this to also output the mean, median, and mode word length.

What Ramp Looks for in Software Engineer Interviews

Ramp Software Engineer interviews are calibrated against the level and scope expected of the role. Across 18+ verified candidate reports on LeakCode, the consistent signals interviewers look for: clear problem decomposition before coding, explicit complexity reasoning, structured handling of edge cases, and the ability to articulate trade-offs between two reasonable approaches.

The discriminator between candidates who advance and candidates who do not is rarely the final correctness of the solution. It is the path to the solution: did you ask clarifying questions, did you state your approach before coding, did you handle edge cases without prompting, and did you communicate your reasoning throughout. Reports tagged "no hire" frequently cite a working solution with poor communication; reports tagged "strong hire" cite clear thinking even when the final solution was incomplete.

How To Use This Question Set

Real interview reports are a calibration tool, not a memorization target. Companies update their question pools every 2-4 months; memorizing exact problems risks misleading you when the interviewer uses a variant. The high-leverage use: identify the patterns that appear repeatedly in Ramp Software Engineer reports, practice those patterns on similar (not identical) problems, and use the reports to understand the interviewer's typical follow-up depth.

Filter the questions below by round type, difficulty, and recency. Focus first on reports from the past 6-12 months; older reports may reference questions that have since rotated out of Ramp's pool. Reports tagged with quantified difficulty (e.g., "medium-hard") are higher-signal than reports without difficulty tags.

Round-by-Round Expectations

Ramp Software Engineer loops typically span 4-6 rounds across phone screens and on-site or virtual on-site interviews. The structure varies by company: some run 1 recruiter screen + 1 technical phone + 3-4 on-site rounds; others run 1 recruiter screen + 1 OA + 4-5 on-site rounds. The recruiter screen is logistics and culture-light; the technical phone screen is medium-difficulty coding; the on-site loop covers coding, system design (at L4+ levels), and behavioral rounds.

Each round is designed to surface a specific signal. Coding rounds: correctness, code quality, complexity reasoning, communication. System design rounds: requirements clarification, design judgment, operational thinking. Behavioral rounds: ownership scope, leadership, ambiguity tolerance, conflict navigation. Strong candidates explicitly hit each signal dimension out loud during the round; weak candidates focus only on solving the prompt.

Common Interview Mistakes At This Combination

Reports tagged "no hire" at Ramp Software Engineer commonly cite: jumping into code without clarifying requirements, coding silently for 10+ minutes without verbalizing approach, missing edge cases (empty input, single element, very large input, overflow), and producing a working solution that the candidate cannot explain or refactor when probed. Strong candidates avoid these patterns by following a consistent template: clarify, verbalize approach, code with narration, test with examples.

Behavioral and design rounds have their own failure modes. Behavioral: stories that use "we" instead of "I" diluting individual signal, stories with no quantified outcome, defensiveness when probed about failure. Design: not asking clarifying questions, not stating requirements out loud, designing for a single server when the prompt clearly implies scale, ignoring operational concerns (deployment, monitoring, rollback). These show up in roughly half of Ramp Software Engineer interview retrospectives on LeakCode.

See All 18 Ramp Software Engineer Questions

Full question text, answer context, and frequency data for subscribers.

Get Access