Square Software Engineer Interview Guide

Timed coding practice for Square software engineer candidates: full attempts under a clock, then scored against a rubric.

Topics: Square, Software Engineer, Interview Guide

Author: PracHub

Published: 9/22/2026

Square logo
Square · Software EngineerUpdated Sep 24, 2026 · Reviewed by PracHub

Square Software Engineer Interview Guide

Timed coding practice for Square software engineer candidates: full attempts under a clock, then scored against a rubric.

2 rounds · typical prep 1–2 weeks

  1. 1Technical Screen2 questions
  2. 2Onsite3 questions

On this page0% read
01 · Overview

Interviewing at Square

A Software Engineer at Square plays a foundational role in building and scaling the financial infrastructure that empowers millions of merchants and individuals globally. Engineers here do not just write code; they design, deploy, and maintain highly available distributed systems that handle billions of dollars in transactions. From building intuitive merchant-facing ecosystems to optimizing the core payment processing pipelines, your work directly impacts the economic livelihood of businesses ranging from local coffee shops to massive enterprise sellers. Square candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Practice bank
5+ questions
Rounds
2
Typical prep
1–2 weeks
Interview reports
2
02 · Topic breakdown

What Square actually tests for

Share of 5 Software Engineer questions
  1. Coding & Algorithms60% · 3
  2. Behavioral & Leadership40% · 2
03 · Question bank

The questions most likely to come up

5+ in the Square bank · sorted by popularity
  1. Implement transaction network queriesYou are building a small in-memory library to track pairwise customer transactions and answer connectivity questions about who has transacted with…Coding & AlgorithmsTechnical ScreenCodingHard
  2. Explain an AI-Assisted Engineering Workflow You Can DefendChoose a recent engineering project that you personally worked on. Use it to explain the full path from an ambiguous problem to a maintained…Behavioral & LeadershipOnsiteMedium
  3. List the Two-by-Two Blocks Covering Each Black CellCoding & AlgorithmsTechnical ScreenPremiumEasy
  4. Lead a High-Leverage Project in a Regulated Legacy SystemPrepare a senior-level project deep dive. The project should have meaningful business impact, multiple contributors, and at least one performance,…Behavioral & LeadershipOnsiteMedium
  5. Build a Trust-Aware BIN DatabaseImplement processbinoperations(operations) for an in-memory database of card-number prefixes. A prefix identifies attributes such as card brand and…Coding & AlgorithmsOnsiteCodingMedium
Practice 5+ Square questions

The 60-second brief

A Software Engineer at Square plays a foundational role in building and scaling the financial infrastructure that empowers millions of merchants and individuals globally. Engineers here do not just write code; they design, deploy, and maintain highly available distributed systems that handle billions of dollars in transactions. From building intuitive merchant-facing ecosystems to optimizing the core payment processing pipelines, your work directly impacts the economic livelihood of businesses ranging from local coffee shops to massive enterprise sellers.

Square candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

What a Software Engineer does at Square

The engineering organization at Square operates with a strong emphasis on developer autonomy, collaborative problem-solving, and pragmatic craftsmanship. Rather than working in isolated silos, you will collaborate closely with product managers, designers, and adjacent platform teams to solve complex, real-world commerce challenges. The scale and critical nature of these financial services require a relentless focus on system reliability, clean API design, and robust security practices.

Preparing for this role means aligning yourself with 's unique engineering culture, which prioritizes working software, test-driven development, and extreme collaboration. Whether you are optimizing a database query for high-throughput transactional ledger systems or building seamless user interfaces, you will be expected to think critically about system trade-offs and user empathy.

The Square interview process

Square candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Recruiter Call

The title covers product work, platform work, infrastructure, mobile and frontend, and those are different jobs with different loops behind them. A screening call is the cheapest place to find out which one the seat is, and asking reads as experienced rather than fussy. The questions that separate them: what the team is on call for, what the last three projects were, and whether any round happens inside an existing repository instead of a blank file. Then say which of that you have done and which you have not. Claiming the whole posting is the fastest way to be found out one round later.

What it evaluates

  • Whether you can locate your experience inside one flavour of the role honestly instead of claiming the entire requirements list
  • Whether you name what you have not done, which an experienced screener reads as a level signal and can plan the loop around
  • Whether what you want next matches what the seat is: someone who wants greenfield work landing on a team that mostly operates an existing system is a hire that leaves within the year

How to prepare

  • Mark every line of the posting as done, adjacent or new, and write one sentence for each adjacent line naming the closest thing you actually built
  • Split your last two years into rough percentages across feature work, operating and debugging live systems, and design or review, so a question about scope gets numbers rather than adjectives
  • Bring three questions that discriminate between seats: what the team is paged for, how much of the work is changing existing code versus standing up something new, and what shipped in the last quarter

Technical Screening

Input bounds are the part of the prompt most often skimmed, and they usually contain the answer. They tell you which complexity class is admissible, which narrows the search before you have thought about the problem itself. As a rough planning figure, a compiled language does on the order of 10^8 simple operations per second and an interpreted one roughly an order of magnitude less. So n up to about twenty admits enumerating subsets, a few thousand admits a quadratic pass, and a million admits neither: you need near-linear, or linear with a log factor. If the bounds are missing, ask for them.

What it evaluates

  • Whether the approach is justified by the stated input size rather than by whichever pattern you recognised first
  • Whether you ask about the properties that change the algorithm: whether the input arrives sorted, whether duplicates occur, whether values are bounded integers, whether it all fits in memory
  • Whether you can name the bottleneck in your own solution and what would remove it, even when you deliberately leave it in place
  • Whether a claimed speedup is real, since memoising a recursion only helps when subproblems genuinely overlap and the state can be keyed cheaply

How to prepare

  • For each algorithm you rely on, write down the largest n it handles in roughly a second, then check two of those figures by timing them in the language you will actually type in
  • For two weeks, write one line naming your target complexity and the bound that justifies it before you write any code, then compare that line with what you ended up submitting
  • Practise the conversion backwards: given a required O(n log n), list the mechanisms that get you there (sorting, a heap, an ordered map, divide and conquer) and choose by what the problem needs to query, not by what you used last

Virtual Onsite Loop

Coding rounds mostly set a floor. They decide whether you clear the bar, not where you land on the ladder. Level tends to come out of the design discussion and the ownership stories, so the question worth auditing beforehand is whether the scope you describe matches the scope of the job. Work that stops at your own service, or a story whose hard part was writing the code rather than getting several people to agree on an interface, reads a level below where you think you are interviewing, and that gap is usually resolved downwards.

What it evaluates

  • Whether the largest thing you describe owning ran end to end — the decision, the migration path, the rollout, and what you did when it went wrong — or stopped at the change you merged
  • Whether design answers include what you would not build, what you would defer, and what you would measure before committing, rather than only what the boxes are
  • Whether a disagreement in a story was settled with something checkable — a benchmark, a prototype, a written proposal — instead of by seniority or by waiting it out
  • Whether you can say which calls you made alone and which you escalated, and why the line sat where it did

How to prepare

  • Write your largest piece of owned work as a timeline of decisions — who decided what, when, and what you did when the plan broke — then delete every sentence whose subject is "we" and see how much survives
  • Take one system you know well and drill the migration answer: how old and new paths run side by side under live traffic, how you compare their outputs, what the rollback is once writes are going to both, and which step you would not automate
  • Map each line of the ladder in the job posting to a specific thing you have done, find the line you cannot support, and prepare the closest evidence you have plus an honest account of the gap

Questions Square candidates report

These are the prompts PracHub has collected for this role and company. They are a record of what candidates describe being asked, so treat them as the shape of the conversation rather than a script Square works from.

Data structures and algorithms

State the bound, then read your own code against it, because the cost you forgot is usually inside a call you did not write. A membership test against a list is linear while the same test against a set is expected constant, so one of those inside a loop turns a linear scan quadratic. Taking a slice copies the elements wherever slices are values rather than views. Repeated string concatenation is quadratic wherever strings are immutable, unless you accumulate into a builder or a list and join once. None of that is visible in the shape of the algorithm, and all of it is visible in the runtime.

  • Implement a versioned key-value store that allows retrieving values at a specific point in time.
  • Implement a stream processing pipeline using a HashMap to aggregate unique daily events while ignoring timestamps.
  • Build a basic rate limiter or request-throttling mechanism to protect a simulated API endpoint.
  • Write a program to represent a player on a game board, handle movement inputs, and enforce board boundaries.

System design and architecture

Turn the prompt into a workload before drawing anything: requests per second at peak, the read to write ratio, the size of one stored object, how long it is kept, and how each of those grows. Those numbers decide the architecture, and without them every component is a guess. Size the simplest thing that fits, then add a tier only where a number says the simple version breaks. What separates a strong answer is that every box has a quantity attached to it. A cache, a queue and a partition scheme that each answer a specific number read as judgement; the same diagram without numbers reads as recall.

  • Design a hotel reservation and booking system that handles concurrent bookings and prevents double-booking.
  • Design a real-time stock market or trading platform emphasizing low latency, high consistency, and auditability.

Practice exercises with worked solutions

The prompts above tell you what gets asked. These are PracHub exercises written to drill the same skills, with the reasoning spelled out so you can check your own answer instead of guessing whether it was good enough.

Stop the capture-and-refund join from double-counting merchant money

Report captured_minor, refunded_minor and net_minor per merchant per business_date. payment_intent holds intent_id, merchant_id, amount_minor, captured_minor, refunded_minor. ledger_entry holds transaction_id, account_id, direction, amount_minor, source_type in (capture, refund, fee, chargeback), source_id = the intent_id as text, and business_date; every capture posts one debit and one credit. A draft joins payment_intent to ledger_entry twice, once filtered to captures and once to refunds, and sums both. On intents with two partial captures and one refund the totals are wrong. Name both multiplications precisely and write the correct query.

How a strong candidate works it

  • Name the first multiplication by cardinality: intent to capture entries is one-to-N and intent to refund entries is one-to-M, so joining both yields N times M rows per intent. Every capture row is then counted M times and every refund row N times, and the two columns are inflated by different factors, which is why the totals look almost right rather than obviously broken.
  • Name the second, which is easier to miss: double-entry means each capture posts two legs, so summing every entry of a capture counts the amount twice regardless of joins. Select the single leg by ACCOUNT - the merchant's settlement payable, which carries exactly one leg of every capture and of every refund - and not by direction. Direction is not a substitute for that filter: a capture credits the payable and a refund debits it, so adding direction = 'credit' keeps the captures and silently drops every refund leg, leaving refunded_minor at exactly zero on a query that otherwise reads as correct.
  • Reject the reflexive fixes: SELECT DISTINCT and SUM(DISTINCT ...) de-duplicate values, not rows, so two genuine captures of equal amount collapse into one and the total is wrong in the other direction while looking tidier.
  • Prefer a single pass with conditional aggregation over ledger_entry, restricted to that one account: SUM(amount_minor) FILTER (WHERE source_type = 'capture') and the same for refunds, grouped by merchant and business_date, joining payment_intent only to reach merchant_id. One scan, no intent-level fan-out, and fees or chargebacks are added as another FILTER rather than another join. amount_minor is a positive magnitude, so net_minor is captured minus refunded; the signed form over the same rows, SUM(CASE WHEN direction = 'credit' THEN amount_minor ELSE -amount_minor END), returns the same net in one column and is the check on the sign convention.
  • Keep aggregate-then-join in reserve for when per-intent detail is required: aggregate each side to intent grain in its own CTE, then join the two aggregates one-to-one. LATERAL works too and reads better when the right side needs the left's key.
  • Get the account predicate, the join column and the date right. Each merchant has its own settlement payable, so the predicate is a join to the account dimension (a.account_type = 'merchant_payable' AND a.merchant_id = pi.merchant_id); a single $settlement_account literal is only correct for a one-merchant report. source_id is text and intent_id is uuid, and PostgreSQL has no implicit cast between them, so one side must be cast and the side decides which index stays usable - pi.intent_id = e.source_id::uuid probes payment_intent's primary key per entry row, e.source_id = pi.intent_id::text probes an index on ledger_entry(source_id), and if neither fits the driving table the planner hashes both sides, which is fine for a day's report and not for a single-intent lookup. Group on ledger_entry.business_date rather than posted_at::date, because they differ across the cutoff, and decide explicitly whether a later-dated refund reduces its own day or the original capture's.

Follow-ups

  • A refund lands on a later business_date than its capture. Which day does net_minor move, and what does that do to a daily merchant payout?
  • Add scheme fees, which arrive netted into a batch total rather than per transaction. How does the query change, and what can it no longer claim?
  • How would you reconcile this output against payment_intent.captured_minor, and which one is authoritative when they disagree?

Rebuild a statement with a running balance from entries alone

From ledger_entry(entry_id bigint and monotonic, account_id, direction, amount_minor, currency, business_date, posted_at) produce one month's statement for a single account: every entry in order, its signed amount, and the running balance after it, starting from a supplied opening balance. The account is a customer deposit, so a credit increases it. Also return the first business_date in the month on which the running balance went negative, or null if it never did. Write the query using window functions, state which frame you depend on, and say what makes the ordering deterministic.

How a strong candidate works it

  • Sign the amount first: CASE WHEN direction = 'credit' THEN amount_minor ELSE -amount_minor END, because the sign lives in direction and never in the column. State the convention out loud, since a customer deposit is a liability of the institution and a credit increases it, while for an asset account the same expression inverts.
  • Compute the running balance as SUM(signed) OVER (PARTITION BY account_id ORDER BY business_date, entry_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), then add the opening balance as a scalar. The opening figure is a constant for the statement, not a second window.
  • Be explicit about the frame, because it is the whole exercise: with an ORDER BY and no frame clause the default is RANGE UNBOUNDED PRECEDING AND CURRENT ROW, which includes every peer row tied on the ordering key. Ordering on business_date alone therefore reports the same end-of-day figure on every line of that day, and the statement still looks plausible.
  • Make the order deterministic with a column that has no ties: business_date has ties by construction, entry_id is monotonic and unique, and posted_at is neither guaranteed unique nor correct as an ordering key when a backdated entry posts late.
  • Get the first breach from the same computation rather than a second pass: wrap the running balance in a subquery and take MIN(business_date) FILTER (WHERE running_balance_minor < 0). LAG is the wrong tool here, because the question is about a level rather than a change.
  • Support it with an index on (account_id, business_date, entry_id) so the partition and the order both come from the index; then confirm in EXPLAIN that there is no Sort node above the index scan.

Expected result (25 min): One row per entry in date then entry_id order. The final row's running balance equals the opening balance plus the sum of all signed amounts in the month, to the minor unit. first_negative_date is the earliest business_date at which the ordered running balance dipped below zero, and null when it never does.

Check yourself

  • Sum the signed column independently with a plain aggregate and compare it against the last running balance; they must be equal.
  • The three entries sharing a business_date show three different running balances, which proves the frame and tiebreak are right.
  • Removing the ROWS frame reproduces the end-of-day artefact on exactly those three rows and nowhere else.
  • EXPLAIN shows no Sort node above the index scan on (account_id, business_date, entry_id).

Follow-ups

  • An entry for 3 March posts on 7 March, after the statement for that week was sent. Where does it appear, and what does the running balance do?
  • The same statement has to be reproducible a year from now. What stops it changing, and what would silently change it?
  • At what account size does deriving this per request stop being viable, and what would you materialise first, a daily closing balance or a monthly one?

Detect duplicate-charge bursts in an out-of-order authorisation stream

Authorisations arrive as (instrument_token_id, amount_minor, currency, event_time, arrival_time) at roughly 3,000 per second, up to 60 seconds late and out of order. Flag any token with three or more authorisations of identical (amount_minor, currency) inside any 10-minute window of event time. Report each flag once, as early as correctness allows. State memory per key and in total, how late an event you will accept, and what you do with one that arrives after you have already reported — or already declined to report — that window.

How a strong candidate works it

  • Key state by (instrument_token_id, amount_minor, currency), not by token: the predicate is about identical amounts, so the window belongs to the triple. Each key holds its own event-time-ordered deque.
  • In-order, this is two pointers: on insert, pop from the front while front <= new - 10 min, then flag if the deque reaches length 3. Amortised O(1) per event, memory proportional to that key's window occupancy.
  • Out-of-order arrival breaks append-only monotonicity, so insert in position instead. With lateness bounded at 60 seconds the insertion point is always near the tail, so a short sorted vector or a 600-bucket per-second ring keeps it O(w) with tiny w; a balanced tree per key is correct but over-built for a one-minute reorder.
  • Drive decisions off a watermark of max(event_time seen) - 60 s, never off wall clock. Anything older than the watermark is too late to change an answer and is counted in a late_dropped metric. Without an explicit watermark you have still chosen a lateness policy — you just cannot state it or test it.
  • Report-once needs its own state: per key, a set of already-flagged 10-minute window ids. A later event inside an already-flagged window must not re-flag, and a late event that completes a window you never flagged must flag — which is why state is retired at window close plus the lateness bound, not at window close.
  • Size it: state lives 660 seconds, so at 3,000 events per second there are about 1.98 million in flight, plus one flagged-window set per active key. Bound total memory explicitly and shed by key age, and say what shedding costs — a shed key can miss a flag, making the threshold a product decision rather than a tuning knob.

Expected result (40 min): Fixture 1 flags exactly once, at the t+9 event; the t+11 event does not flag under the half-open rule and does under the closed one, which is the boundary the fixture exists to pin. Fixture 2 yields the same single flag with the same window id. Fixture 3 yields no flag and late_dropped == 1. All twenty shuffles produce an identical flag set.

Check yourself

  • Replaying the same events in any arrival order within the lateness bound produces identical flags — the only property that makes this job re-runnable.
  • Per-key state never exceeds that key's events within 660 seconds; assert it rather than hope.
  • Every flag's window id derives from event time alone; arrival_time appears only in the watermark computation and the lateness metric.

Follow-ups

  • Make the threshold and window configurable without rebuilding all in-flight state on every change. What does that constrain in the data structure?
  • Two stream partitions hold events for the same token. What does that force the partitioning key to be?
  • An event arrives three hours late. Does any answer change, and who is told?

Paginate an append-only statement endpoint under continuous writes

Statement reads come from ledger_entry (entry_id bigint monotonic primary key, transaction_id uuid, account_id bigint, direction, amount_minor bigint, currency, source_type, source_id, business_date date, posted_at timestamptz). The caller is a merchant dashboard fetching one account newest-first, 100 rows per page, while new entries are still being appended. Offset pagination is in production and support reports rows appearing on two consecutive pages. Design the replacement: the index, the exact WHERE clause and ORDER BY, the cursor's contents and encoding, and what happens when a caller reuses a cursor an hour later.

How a strong candidate works it

  • Name the mechanism of the duplication rather than blaming the sort. Each page is a separate statement with its own snapshot; under a descending order, every row inserted between page 1 and page 2 shifts the whole result one position later, so the last row of page 1 reappears as the first row of page 2. The cost is bad too: OFFSET n scans and discards n rows, so deep pages are O(offset + k).
  • Replace it with a keyset predicate over the unique, monotonic ordering column: WHERE account_id = $1 AND entry_id < $cursor ORDER BY entry_id DESC LIMIT 100. That is one index descent plus 100 rows, O(log n + k), and the cost does not change with depth.
  • Index (account_id, entry_id). A B-tree is scanned in either direction at the same cost, so a separate DESC index buys nothing. If the endpoint also filters on a date range, the tuple becomes (account_id, business_date, entry_id) and the predicate becomes a row-value comparison, (business_date, entry_id) < ($d, $e), which still resolves to a single descent.
  • Make the cursor opaque and self-describing: base64 of the anchor tuple plus a hash of the filter set and an encoding version. A cursor presented with a different account or date range is rejected with a distinct code rather than quietly returning another account's rows.
  • State the validity rule. Because the table is append-only, the anchor row is never deleted, so a keyset cursor stays valid indefinitely and an hour-old cursor simply resumes. Add one caveat for machine consumers: entry_id is allocated before commit, so an entry with a lower id can become visible after a reader has already passed it. A human statement page never notices, but a feed consumer needs a lag window or a commit-ordered marker rather than the newest id.

Expected result (25 min): Keyset returns every pre-existing entry exactly once across pages under concurrent appends, and EXPLAIN shows a constant buffer count for keyset at any depth while OFFSET's buffer count grows linearly with the offset.

Check yourself

  • No entry_id returned on page 1 appears on page 2 when inserts happen between the two fetches.
  • The keyset plan is an index scan with no Sort node and no rows discarded before the limit.
  • A cursor minted for one account or filter set is rejected with its own error code when replayed against another.

Follow-ups

  • The dashboard now wants to sort by amount_minor descending. What breaks, and what does the cursor have to contain to fix it?
  • A caller asks for a total page count. What does that cost on a 400-million-row table, and what do you offer instead?
  • How would you support paging backwards from a cursor without re-sorting in the application?

Approval rate collapses when one feature-store shard fails

The risk decision service answers about 3,000 authorisations per second within an 80 ms p99, reading features from an eight-shard store behind a local cache with a fixed 60-second TTL, a 2-second client timeout and two retries on timeout. One shard becomes unreachable at 14:02. Approval rate falls from 96% to 71% within 90 seconds, and the seven healthy shards show p99 rising to 900 ms with normal error rates. Diagnose in order, name the cause of the approval drop, and state the degraded behaviour this service should have had.

How a strong candidate works it

  • Establish what declined actually means here before touching the cache. Split the rate into approve, decline, refer and timeout. If decline counts are flat and timeouts account for the whole 25-point drop, the model is not declining anything; it is failing to answer, and something downstream is reading silence as a decline. That reading is the first finding and the most expensive one.
  • Break the store's metrics out per shard. One shard at 100% errors and seven at elevated latency with baseline error rates is the signature of queueing, not of seven shards failing. Healthy dependencies with healthy error rates and bad latency are almost always victims of a shared resource.
  • Follow the resource. A single connection or thread pool shared across shards means requests to the dead shard occupy slots for the full 2-second client timeout, which is 25 times the whole p99 budget, and with two retries each such request can hold a slot for 6 seconds. Confirm by comparing pool acquisition wait against per-shard service time: if wait dominates, the pool is the bottleneck.
  • Quantify the amplification. Two retries on timeout offer 3x load, and an unjittered 60-second TTL expires a warm set together, so misses arrive as a synchronised wave rather than spread across the window. Retrying a timeout is only correct when the failure is likely transient; against a hard-down shard it is pure amplification and needs a circuit breaker to gate it.
  • Fix the three separate defects separately: per-shard pools so one shard cannot starve seven, a breaker that stops retrying a shard that is failing, and per-key TTL jitter with single-flight refresh so N concurrent misses for one key produce one upstream read.
  • Write down the degraded decision as a product decision, not a timeout handler's accident. With features unavailable the service must return a stated answer, such as deterministic rules alone below an amount threshold and refer above it, and must record that the decision was degraded so it is auditable and reproducible from stored inputs.

Follow-ups

  • Approving on deterministic rules alone during a feature outage carries a fraud cost. How do you size the amount threshold, and who signs it off?
  • What should the orchestrator do with a risk timeout, given it cannot distinguish one from a decline?
  • Does the circuit breaker fix the healthy shards' latency, or is the bulkhead doing that work? Which would you ship first if you could only ship one?

Own the postmortem for a duplicate-capture incident

A processor slowed down, callers timed out and retried without reusing their idempotency key, and 412 captures were duplicated over 90 minutes before a reconciliation break report surfaced it. Take the on-call role. Describe an incident you owned of comparable blast radius: how it was detected, how you bounded the affected population, what you stopped first, and how customers were made whole. Give a wall-clock timeline, the query or metric that sized the damage, and the change that would have prevented it. Include what you got wrong during the response, not only after it.

How a strong candidate works it

  • The probe is whether you can bound an unknown blast radius under time pressure. Open with the invariant that broke (at most one capture per authorisation attempt) rather than the symptom, because the invariant tells the listener what to count.
  • Size the population with a stated query, not an adjective: duplicate captures are ledger_entry rows with source_type='capture' grouped by source_id having count(*) > 1, joined back to payment_intent for the affected merchants and amounts. Say how long that query took and whether you could run it against a replica while the incident was live.
  • Separate mitigation from fix and say which you did first. Mitigation is usually cheap and blunt (disable the retry path, drop the caller's concurrency, hold captures behind a flag); the fix is a UNIQUE constraint plus a stored response, and it is not an incident-window change.
  • State the remediation arithmetic explicitly: refunds are new customer-visible movements with their own fees and their own settlement lag, so the count of duplicates, the total minor units, the refund posting date and the customer notification are four separate numbers a strong answer has ready.
  • Close on the prevention change and its cost. Naming one guard that would have caught it earlier (a break-age alert, a duplicate-capture counter on the ledger write path) beats listing five that nobody staffed.
  • Name your own error inside the response window: a mitigation you tried that made it worse, or the 20 minutes you spent on the wrong hypothesis. Interviewers weight that heavily because it is the part candidates rehearse away.

Follow-ups

  • The retry came from a client you do not control. What do you change so a client that regenerates its key per attempt cannot cause this again?
  • How would you have detected it in 5 minutes instead of 90, and what would that detector cost in false pages per week?
  • A merchant disputes your count of affected transactions. What do you show them?

Unblock an engineer on double-posted interest accrual

An engineer two years into their career has a nightly accrual job that double-posts interest for some accounts whenever the batch is partially re-run after a failure. They have spent two days on it and are now rewriting the batch runner. You have 30 minutes. Describe how you have unblocked someone without taking the keyboard: the question you asked first, how you chose between handing over the answer and handing over the method, what you left behind so the next person does not get stuck here, and how you knew they were unblocked rather than deferring to you.

How a strong candidate works it

  • The probe is whether you grow people or absorb their work. Open with the diagnostic question rather than the solution: ask what identifies one unit of work, because the answer reveals immediately that accrual is keyed by (account_id, accrual_date) and that the job has no uniqueness on it.
  • Redirect from the runner to the write. The rewrite is aimed at never re-running, which is unachievable; the property needed is that re-running posts nothing new, enforced by a unique index on (account_id, accrual_date) or by passing the same idempotency key to the ledger posting operation so the second attempt is a no-op rather than a second transaction.
  • Choose deliberately between answer and method and say why. Two days in and blocked on the wrong layer is usually the moment to hand over the framing (restartable at account granularity, idempotent per unit) and let them write the code, because the lesson is the framing and the code is the easy part.
  • Leave an artefact, not a conversation: a test that re-runs one account twice and asserts one posting, plus two lines in the runbook stating that per-account work must be idempotent because the batch is always partially re-run.
  • Check that they are unblocked by asking them to predict the failure that the fix does not cover, such as a mid-run rate change producing two different correct amounts for the same key. If they can find the next edge themselves, they own it; if they ask you to confirm each step, they are deferring and you have hidden the block rather than removed it.
  • Say what you deliberately did not do. Not fixing it yourself before the standup is the whole exercise, and a strong answer names the pressure it resisted.

Follow-ups

  • The unique index rejects the re-run, but the first run posted the wrong amount. How should the job behave now?
  • How do you tell whether you taught them or just unblocked them, a month later?
  • The same engineer is blocked again next week on a similar problem. What does that tell you about your first intervention?

Ship payouts with named, scheduled reconciliation debt

You have six working days to ship merchant payouts. The correct reconciliation join is on (external_reference, amount_minor, currency, business_date); the version that fits the window matches on amount and business_date alone, which will mismatch same-amount, same-day lines. Describe a time you shipped with debt you knew about. State exactly what you cut, the guard that made the shortcut visible rather than silent, who agreed to carry the risk, the date it was paid down, and what it cost while it stood. Be specific about the failure you were accepting.

How a strong candidate works it

  • The probe is whether your shortcuts are bounded and instrumented or merely undocumented. Start by stating the failure you accepted in one concrete sentence: ambiguous matches will be resolved arbitrarily, so a genuine break can be masked by pairing with the wrong line.
  • Make the shortcut loud rather than silent. When more than one candidate matches, do not pick one: open a break of type duplicate_match and emit a counter on that path. A shortcut that reports its own frequency converts an unknown into a number you can bring to the paydown conversation.
  • Bound the exposure before you ship: query historical settlement files for lines that collide on (amount_minor, business_date) within a merchant. If that is 0.2 percent of lines, the risk is small and quantified; if it is 8 percent, the plan does not survive contact and you have learned that before shipping rather than after.
  • Name the owner and the date, and say where they are written down. 'The team agreed' is the generic answer; a ticket with an owner, a date, and the counter that forces the conversation is the strong one.
  • Distinguish debt you can pay from debt that compounds. A matching shortcut that leaves breaks visible is recoverable; one that auto-resolves breaks by widening a tolerance destroys the evidence and cannot be unwound later, and a strong answer says it would have refused that version even under the deadline.
  • Report the actual cost: how many ambiguous matches occurred, how much analyst time they consumed, and whether the paydown date held. If it slipped, say by how long and what finally forced it.

Follow-ups

  • The paydown date arrives and the team has a new deadline. What do you do differently from the first conversation?
  • Which shortcut would you have refused to ship at any deadline, and why that one?
  • How would you have sized the exposure if no historical settlement files were available?

Where candidates lose points

Treating money as a decimal with two places

ISO 4217 exponents are 0 for currencies such as JPY and KRW, 2 for most, and 3 for BHD, KWD, JOD, OMR and TND, so a hard-coded multiply-by-100 is off by a factor of 100 or 10 depending on the currency, in opposite directions. Floating point is worse: IEEE 754 binary64 cannot represent 0.1 exactly, so repeated accrual accumulates drift that appears as a handful of minor units in the daily reconciliation and then gets 'fixed' by widening the match tolerance, which is how a genuine break becomes invisible. The only forms that survive a reconciliation are integer minor units with the exponent carried alongside the currency code, or a fixed-scale decimal type with exactly one documented rounding point.

Retrying a charge after a timeout

A timeout is not a failure; it is an unknown outcome, and the request may have been processed in full with only the response lost. Re-sending it without an idempotency key that the processor itself honours produces a duplicate charge, which is a customer-visible incident and usually a dispute. The correct handling is to treat the state as unknown, query the processor for that key or client reference, and only then decide. The mechanism also depends on the key being generated once by the caller and reused across every attempt — generating a fresh key per retry turns the whole scheme into a no-op while leaving all the code that appears to implement it in place.

A cache with no invalidation story

Say how an entry goes stale, how long you can serve it stale, and what happens when many requests miss the same key at the same instant. One popular key expiring under load sends every concurrent request to the origin together; single-flight coalescing, jittered expiry, or serving stale while revalidating are the standard answers.

Arguing past a hint

When the interviewer asks what happens for a particular input or floats a different data structure, stop and take it seriously; it is almost always a correction rather than idle curiosity. Talking over it converts a recoverable wrong turn into a data point about how you handle review.

Evenings only, compressed around a full-time job

Roughly ninety minutes on weeknights with one longer weekend block. The plan cuts scope rather than compressing everything, on the assumption that one thing finished per night beats four half-started.

Day 1 — Fix the scope and take a cold baseline

  • Read the role description and write the three things the loop will almost certainly test, then write an explicit not-doing list and keep it visible all week.
  • Take one twenty-five-minute coding problem and one fifteen-minute design prompt cold, and write the single sentence naming what blocked each, because those two sentences decide where the remaining evenings go.
  • Set the week's rule: one thing finished every night, including the night you only have forty minutes.

Deliverable: A one-page scope with a not-doing list and two cold attempts, each carrying one sentence on what blocked it.

Day 2 — One pattern, written three times from blank

  • Choose the single pattern most likely to appear in your loop and write it three times from an empty file rather than editing the previous attempt.
  • On the third pass, write the invariant as a comment before the loop body and the complexity before the first line of code.
  • Stop at ninety minutes even if the third version is imperfect, and write the one thing you would fix given another hour.

Deliverable: Three independent implementations of the same pattern plus a note on what changed between them.

Day 3 — One design, only to the depth you can defend

  • Take one system shape and go only as far as requirements, interface and data model, refusing to draw a box you could not survive a follow-up about.
  • Attach one number to each non-functional requirement, deriving it rather than asserting it, and write the assumption the number rests on.
  • Write the one tradeoff you are choosing against and the observation that would make you reverse it.

Deliverable: One design at interface-and-schema depth with derived numbers and one written reversible tradeoff.

Day 4 — Only the fundamentals you will have to defend

  • Write, in under two hundred words each, the answers to the two questions that follow almost any implementation: why this structure and not the obvious alternative, and what happens to this code at a hundred times the input.
  • Write what an index actually costs: faster lookups on the indexed columns against a write that now maintains a second structure, plus the cases where the planner declines to use it anyway, low selectivity, or a predicate wrapping the column in a function.
  • Delete any answer you cannot deliver aloud in under a minute, since an answer that needs reading is not an answer you have.

Deliverable: Three written answers, each under two hundred words and each timed aloud.

Day 5 — Your own work, timed

  • Write a ninety-second and a four-minute version of your main project and time both aloud rather than reading them.
  • Prepare the two follow-ups that always come: what you would do differently, and how you knew it worked.
  • Put one number in the first sentence and be ready to say exactly where it came from and what it excludes.

Deliverable: Two timed narratives with one defensible number in the opening line.

Day 6 — The one full rehearsal, in the weekend block

  • Run a sixty-minute mock covering a coding round and a design round in one sitting with no break, because sustained attention is the thing evenings have not trained.
  • Immediately afterwards, and before hearing any feedback, write the three moments you lost the thread.
  • Spend the rest of the block only on those three moments, and on nothing you merely feel shaky about.

Deliverable: Mock notes naming three failure moments with a specific fix written under each.

Day 7 — Taper

  • Write the twenty-minute warm-up you will actually do on the morning: one problem you can already solve from a blank file, one design you can narrate, and nothing you have never seen.
  • Re-read only your own notes from this week and open no new material.
  • Write the logistics down: the editor or shared document you will be working in, whether execution and lookups are permitted, and the sentence you will use when you do not know something.

Deliverable: A one-page card holding the design structure, the project numbers, and the logistics.

Frequently asked questions

Is this an official Square interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at Square. Rounds and questions reflect what candidates have reported, not a process Square has published, and they change over time. Confirm the current format and scope with your recruiter.

How difficult is the Software Engineer interview at Square?

The interview is generally rated as average to difficult. Rather than testing you on highly theoretical LeetCode-style brain teasers, Square focuses on practical coding, system design, and collaborative pairing. The difficulty lies in your ability to write clean, working code while explaining your thought process clearly in real time.

Can I use any programming language I want during the coding rounds?

Yes. Square's coding interviews are language-agnostic. You are encouraged to use the language you are most comfortable with. However, ensure that you are familiar with compiling, running, and importing basic packages in that language within the CoderPad environment before your interview.

What is the typical timeline for the hiring process?

The entire process, from the initial recruiter screen to a final decision, typically takes between 3 to 6 weeks. Delays can sometimes occur during team-matching phases or when scheduling multiple onsite rounds, so maintaining active communication with your recruiter is highly recommended.

How does Square evaluate remote or hybrid working arrangements?

Square (under Block, Inc.) supports a highly flexible working model. Depending on the team, location, and role, options include fully remote, hybrid, or office-based arrangements. Your recruiter will discuss the specific location requirements and expectations for your target team early in the process.

Keep practising

More questions candidates ask

No. It is PracHub's own research and practice material for the Software Engineer role at Square. Rounds and questions reflect what candidates have reported, not a process Square has published, and they change over time. Confirm the current format and scope with your recruiter.

The interview is generally rated as average to difficult. Rather than testing you on highly theoretical LeetCode-style brain teasers, Square focuses on practical coding, system design, and collaborative pairing. The difficulty lies in your ability to write clean, working code while explaining your thought process clearly in real time.

Yes. Square's coding interviews are language-agnostic. You are encouraged to use the language you are most comfortable with. However, ensure that you are familiar with compiling, running, and importing basic packages in that language within the CoderPad environment before your interview.

The entire process, from the initial recruiter screen to a final decision, typically takes between 3 to 6 weeks. Delays can sometimes occur during team-matching phases or when scheduling multiple onsite rounds, so maintaining active communication with your recruiter is highly recommended.

Square (under Block, Inc.) supports a highly flexible working model. Depending on the team, location, and role, options include fully remote, hybrid, or office-based arrangements. Your recruiter will discuss the specific location requirements and expectations for your target team early in the process.

SquareSoftware EngineerInterview Guide