</> MAANG.io
system design · 301

Advanced

Master system design interviews with scalable architecture patterns, distributed systems, and real-world design challenges.

0/480 solved 0% complete

Section 4: The 2.8 KB Question - API Design

Executive Summary: Section 3 showed that the load lives in update checks (420,000/s peak) and update bytes (77% of egress), not in browsing, so the contracts are designed in that order. Three families serve three customers. The device family answers "anything new for me?" with a POST that carries the installed list and returns server-chosen delta-or-full files at immutable, content-addressed URLs, plus a server-dictated time for the next check. The storefront and commerce family keeps reads cacheable and makes the one money-moving call idempotent. The developer family is transactional: an edit stages binary, listing and rollout, then commits them as one submission. Four pushbacks test the shapes, and each one ends in a decision with a rejected alternative and a flip trigger.

The interviewer slides the marker across. "Show me the API." The tempting answer is a resource list: apps, users, reviews, purchases. That list is the Catalog Clerk's API, where every resource looks equally important. Section 3's arithmetic says they are not, so the candidate starts from the traffic instead.

Family Key endpoints Peak rate (ledger) What the shape optimises for
Device updates:check, installs, device-profiles 420k checks/s, 150k downloads/s Statelessness, tiny requests, immutable byte URLs
Storefront apps/{package}, search, storefront/home 174k views/s, 35k searches/s Edge cacheability
Commerce purchases, entitlements, reviews 1,740 purchases/s, 350 reviews/s Correctness: idempotency, server-side truth
Developer edits, tracks, :halt 1.7 submissions/s Atomicity and an instant brake

The Device Contract: One Profile, One Question

Before a phone asks about updates, it describes itself once:

POST /v1/device-profiles
{ "abis": ["arm64-v8a"], "densityDpi": 420, "sdkInt": 34,
  "locales": ["hi-IN", "en-IN"], "features": ["android.hardware.location.gps", "..."] }

200 OK
{ "deviceProfileId": "dp_7c41e9" }

The deviceProfileId is a hash of the configuration, not an identity. Every Pixel 7 on Android 14 with the same locales gets the same ID, so profiles are shared by millions of devices, cacheable everywhere, and safe to log. The device's own pseudonymous identity travels separately in its auth token, because the rollout cohort hash(deviceId, releaseId) mod 10,000 needs it and nothing else does.

Here is Priya's check, four times a day, on a check where her cohort is inside the Trailhead Maps 4.3.0 rollout:

POST /v1/updates:check
Authorization: Bearer <device token>
{ "deviceProfileId": "dp_7c41e9",
  "installed": [
    { "package": "com.trailhead.maps", "versionCode": 4210, "certDigest": "sha256:9f2c..." },
    ... 39 more entries, about 2.8 KB in all
  ] }

200 OK
{ "updates": [
    { "package": "com.trailhead.maps", "targetVersionCode": 4300,
      "delivery": { "type": "delta", "fromVersionCode": 4210,
        "files": [
          { "url": "https://cdn-a.example.net/f/3b8e...", "sha256": "3b8e...", "size": 7200000 },
          { "url": "https://cdn-a.example.net/f/c91d...", "sha256": "c91d...", "size": 1800000 },
          ... 3 more patches (xxhdpi, hi, en), a few KB each ] } } ],
  "nextCheckAfterSec": 22417,
  "manifestSignature": "MEUCIQDx..." }

Three fields carry the design. certDigest lets the server refuse to offer an update to a copy whose certificate isn't in the app's signing lineage (a sideloaded, re-signed APK, say). files lists one patch per changed split; the language and density patches are tiny, so the 9 MB is almost all base and ABI, against 38 MB for a full download. And nextCheckAfterSec is roughly six hours plus server-added jitter: the server, not the device's clock, decides when the next question comes, which makes it a load-shedding lever Section 8 will pull. (manifestSignature signs the response with a store manifest key; Section 11 details it.)

Update check sequence: the device posts its 40 installed apps, UpdateCheck looks them up in the in-memory release index and answers with target 4300 as a 9 MB delta plus nextCheckAfterSec, then the device fetches content-addressed patch files from the CDN and verifies sha256 and the APK signature

POST /v1/installs (package, deviceProfileId) returns the same delivery shape for a first install. It is also where entitlement is checked: a paid app's manifest carries short-lived signed URL tokens, so the CDN never has to know who owns what. The update check never reads entitlements: for paid packages it marks the plan as needing tokens, which the device exchanges here.

Quick check before moving on:


Sign in to continue reading

The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.

Sign in to read the full lesson

Sign in to MAANG.io

Use your Google or Microsoft account — no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.