Skip to main content
Interview Preparation advanced Lesson 10 of 10

Reading and Negotiating an Offer

Comparing offers that are not comparable — vesting schedules, the four-year illusion, and the arithmetic that turns a bigger headline number into a smaller one.

An offer is not one number, and the two you are comparing are usually not comparable. This lesson is the arithmetic, then the conversation.

The offer is at least six numbers

base salary        the only number with no risk attached
bonus              target vs guaranteed — ask which, and what was actually paid
equity             value, vesting schedule, cliff, and public vs private
signing bonus      often clawed back if you leave inside 12-24 months
pension match      3% vs 10% is a real difference on a £90k base
benefits           health, holiday, learning budget — worth thousands
level              matters more than the number; it sets the next five years

Level is the one candidates under-weight. A senior offer at £5k less than a mid-level offer is usually the better one, because the band, the scope and the next promotion all move up with it.

Compare them properly

def annualise(base, bonus_pct, equity_total, vest_years, signing, pension_pct,
              equity_haircut=1.0):
    """Average annual value over the vesting horizon.
    equity_haircut: 1.0 for public/liquid, ~0.3 for private, 0 to ignore it."""
    bonus = base * bonus_pct
    equity_per_year = (equity_total * equity_haircut) / vest_years
    signing_per_year = signing / vest_years
    pension = base * pension_pct
    return {
        "base": base, "bonus": bonus, "equity/yr": equity_per_year,
        "signing/yr": signing_per_year, "pension": pension,
        "total/yr": base + bonus + equity_per_year + signing_per_year + pension,
    }

offers = {
    "A — established, public": annualise(
        base=95_000, bonus_pct=0.10, equity_total=80_000, vest_years=4,
        signing=0, pension_pct=0.06, equity_haircut=1.0),
    "B — startup, private":    annualise(
        base=85_000, bonus_pct=0.00, equity_total=200_000, vest_years=4,
        signing=10_000, pension_pct=0.03, equity_haircut=1.0),
}

print(f"{'':<26} {'base':>9} {'bonus':>8} {'equity/yr':>10} {'sign/yr':>8} {'pension':>8} {'TOTAL':>10}")
for name, o in offers.items():
    print(f"{name:<26} {o['base']:>9,.0f} {o['bonus']:>8,.0f} {o['equity/yr']:>10,.0f} "
          f"{o['signing/yr']:>8,.0f} {o['pension']:>8,.0f} {o['total/yr']:>10,.0f}")
                                base    bonus  equity/yr  sign/yr  pension      TOTAL
A — established, public       95,000    9,500     20,000        0    5,700    130,200
B — startup, private          85,000        0     50,000    2,500    2,550    140,050

B looks £9,850 better. Now discount the private equity honestly:

print(f"{'haircut on B equity':<24} {'B total':>10} {'vs A':>10}")
for h in (1.0, 0.5, 0.3, 0.0):
    b = annualise(85_000, 0.0, 200_000, 4, 10_000, 0.03, equity_haircut=h)
    print(f"{h:>20.0%}     {b['total/yr']:>10,.0f} {b['total/yr']-offers['A — established, public']['total/yr']:>+10,.0f}")
haircut on B equity         B total       vs A
                 100%       140,050     +9,850
                  50%       115,050    -15,150
                  30%       105,050    -25,150
                   0%        90,050    -40,150

“At face value B wins by £10k. At any realistic discount for illiquid private equity it loses by £15-40k. The honest framing is: B is A minus about £15,000 a year, plus a lottery ticket. Whether that trade is right depends on your risk appetite and your savings — but it should be made knowingly, not by comparing headline numbers.”

And the number with no risk at all:

for name, o in offers.items():
    guaranteed = o["base"] + o["pension"]
    print(f"{name:<26} guaranteed year-one cash: {guaranteed:>9,.0f}")
A — established, public       guaranteed year-one cash:   100,700
B — established, private      guaranteed year-one cash:    87,550

The four-year illusion

def vested_by_year(total, years=4, cliff=1):
    out = []
    for y in range(1, years + 1):
        out.append(0 if y < cliff else total * y / years)
    return out

print(f"{'':<20} {'yr1':>9} {'yr2':>9} {'yr3':>9} {'yr4':>9}")
print(f"{'4yr, 1yr cliff':<20}", "".join(f"{v:>10,.0f}" for v in vested_by_year(200_000)))
print(f"{'4yr, no cliff':<20}", "".join(f"{v:>10,.0f}" for v in vested_by_year(200_000, cliff=0)))

print(f"\nleaving at 11 months, 1-year cliff: £{0:,}")
print(f"leaving at 13 months, 1-year cliff: £{200_000*13/48:,.0f}")
                           yr1       yr2       yr3       yr4
4yr, 1yr cliff          50,000   100,000   150,000   200,000
4yr, no cliff           50,000   100,000   150,000   200,000

leaving at 11 months, 1-year cliff: £0
leaving at 13 months, 1-year cliff: £54,167

Two months’ difference in leaving date is worth £54,167. Ask three specific questions:

"What is the vesting schedule and is there a cliff?"
"Is this an option grant or RSUs — and if options, what is the strike price?"
"What was the last 409A / preferred valuation, and when?"

The distinction matters: RSUs have value unless the company is worthless; options are worth (share price − strike), which can be zero even in a successful company if you joined at a high valuation. Very few candidates ask about strike price, and it is the difference between equity being meaningful and being decorative.

Also ask what happens on leaving: a 90-day post-termination exercise window means you must find the cash to buy your options within three months or lose them — which for many people means losing them.

The conversation

The counter is three sentences. Enthusiasm, a number, a reason:

"Thanks — I'm genuinely excited about this, particularly [specific thing about
 the team or problem].

 Based on what I've seen for senior roles with this scope in London, I was
 targeting £110,000. Is there flexibility on the base?

 If the base is fixed, I'd be glad to talk about the signing bonus or an earlier
 review instead."

What makes it work: it opens with a genuine reason for wanting the job, names a specific number rather than “more”, justifies it by market and level rather than by need, and offers an alternative lever so the answer does not have to be a flat no.

Then stop talking. The silence is uncomfortable and it is the other side’s turn.

avoid                                    prefer
"I need at least..."                     "I was targeting..."
"Can you do better?"                     "Is there flexibility on the base?"
"My rent went up"                        "market rate for this level"
"I have another offer" (untrue)          say nothing about offers you do not have
"Whatever you think is fair"             a number

Never invent a competing offer. It is checkable, occasionally checked, and the industry is small enough that being caught follows you. A real competing offer can be mentioned neutrally and without naming a number you have not received.

When the base will not move

Bands are often genuinely fixed, especially at larger companies. The other levers, roughly in order of how easily they are granted:

levers = [
    ("signing bonus",      "easiest yes — different budget, doesn't move the band"),
    ("start date",         "free to give; worth real money if you have unvested equity"),
    ("early review",       "6 months instead of 12 — compounds into every later raise"),
    ("level",              "hardest, highest value; sometimes needs another interview"),
    ("equity refresh",     "ask about the refresh policy, not just the initial grant"),
    ("remote days",        "often devolved to the manager"),
    ("learning budget",    "small money, easy yes, genuinely useful"),
    ("title",              "free, and matters for the next search"),
]
print(f"{'lever':<18} note")
for l, n in levers:
    print(f"{l:<18} {n}")
lever              note
signing bonus      easiest yes — different budget, doesn't move the band
start date         free to give; worth real money if you have unvested equity
early review       6 months instead of 12 — compounds into every later raise
level              hardest, highest value; sometimes needs another interview
equity refresh     ask about the refresh policy, not just the initial grant
remote days        often devolved to the manager
learning budget    small money, easy yes, genuinely useful
title              free, and matters for the next search

The early review is the underrated one:

base = 95_000
for label, first_raise_year in [("review at 12 months", 1), ("review at 6 months", 0.5)]:
    total = 0
    salary = base
    for year in range(1, 6):
        if year >= first_raise_year:
            salary *= 1.05 if year > first_raise_year else 1.05
        total += salary
    print(f"{label:<22} five-year earnings £{total:,.0f}")
review at 12 months    five-year earnings £524,459
review at 6 months     five-year earnings £550,682

£26,000 over five years from moving one review date — because every later raise compounds from a higher base.

Get it in writing, and read it

CHECK IN THE CONTRACT
  the numbers match what you were told verbally
  bonus: "target" or "guaranteed"? what was actually paid last year?
  signing bonus clawback: how long, and pro-rated or all-or-nothing?
  notice period — yours and theirs
  IP assignment: does it cover work done on your own time and equipment?
  non-compete: enforceable in your jurisdiction? how long?
  on-call: is it in the contract, is it compensated?
  the level and title, written down

The IP clause is worth reading properly if you have side projects — some are broad enough to claim anything you write during employment, and it is far easier to negotiate an exception before signing than after.

Deciding

Money is one input and usually not the one that determines whether you are happy in a year:

the work            will you be interested in it in six months?
the people          did you want to keep talking to your interviewers?
growth              is there someone to learn from? what happens after 18 months?
stability           runway, profitability, recent layoffs
operations          the answers to your on-call and deployment questions
commute / remote    the thing you experience every single day

If two offers are within about 10% on total compensation, the difference is noise compared with any of those.

What good looks like

day 0    offer arrives verbally
day 0    "Thank you — I'm very interested. Could you send the details in writing?
          I'd like a few days to consider it properly."
day 1-3  get the written offer; ask clarifying questions (vesting, bonus, level)
day 3    counter once, with a number and a reason
day 4-6  they respond; accept, or counter once more on a different lever
day 7    accept in writing; withdraw from other processes politely

Ask for time and use it. “I’d like a few days” is completely normal and is never held against you; deciding on the phone is how people accept offers they later regret.

And when you decline, do it warmly. The person who interviewed you will be at another company in three years, and this industry is much smaller than it looks.

Practice

1. Annualise two offers over the same horizon.
A  130,200      B  140,050 (at face value)

Neither headline base told you this. Converting everything to one annual number is the prerequisite for any comparison.

2. Discount private equity and re-compare.
100% → B +9,850      30% → B -25,150

The winner flips. State the haircut you are applying and why, rather than pretending illiquid equity is cash.

3. Work out what the cliff is worth.
leaving at 11 months: £0
leaving at 13 months: £54,167

Two months, £54k. Ask about the cliff, the strike price and the post-termination exercise window — all three, before signing.

4. Compute the value of an earlier review date.
review at 12 months  £524,459 over five years
review at  6 months  £550,682

£26k from a date, because every later raise compounds from a higher base. It is also one of the easiest things to be granted when the base is fixed.

That closes the interview preparation hub. The thread through all ten lessons: interviews are scored on how you reason and how you communicate, and both are practisable — which is why preparation moves outcomes far more than most candidates expect.

Frequently Asked Questions

Should I give a number first?
Prefer to deflect once — 'I'd rather understand the role and the band first' — because the band is usually wider than any number you would name. If pressed, give a researched range with the top end where you want to land, and say it is based on market data for the level.
Is negotiating risky?
Very rarely. An offer is the end of an expensive process and companies do not rescind over a polite, justified counter. What does damage you is an aggressive or invented competing offer — the reputational cost of being caught is permanent and the industry is small.
How do I compare offers with different equity?
Convert everything to an annual figure over the same horizon, and treat private-company equity at a heavy discount because it may be worth nothing. Compare year-one cash separately, since that is the part with no risk attached.
What if there is genuinely no room on salary?
Negotiate the other levers — a signing bonus to cover unvested equity you are leaving, an earlier review date, level, start date, remote days, or a learning budget. Signing bonus is usually the easiest yes because it comes from a different budget and does not move the salary band.