Introduction
I’m not a PayPal engineer. (I am interested tho if a paypal recruiter is reading this.) I just like system design who’s read some case studies, conference talks, and architecture blog posts. One story that really caught my eye is how PayPal pivoted from a chatty REST architecture, flirted briefly with a custom “Bulk REST” layer, and ultimately moved to GraphQL, cutting their checkout flow latency and boosting developer productivity. In this post, I’ll try to unpack that evolution step by step, complete with restaurant analogies, real world numbers, and key takeaways you can apply to your own APIs.
What Is REST? (The “Waiter” Model)
Imagine you walk into a diner and sit down. Here’s how a typical REST style experience works:
- You ask the waiter for a cheeseburger.
- The waiter walks to the kitchen and brings back your burger.
- You then ask for fries. The same waiter makes another back and forth trip.
- You ask for a soda. Yet another trip.
In REST:
- Each dish = one HTTP request to a specific endpoint.
- Every round trip takes time — network latency, server processing, etc.
- Apps become “chatty” when they need half a dozen resources to render a single page.
At PayPal scale, those extra waiter trips added up: they measured ~700 ms per REST round trip at the 99th percentile. Imagine waiting almost a full second every time your app fetched user info, funding sources, and shipping addresses one by one!
What Is GraphQL? (The “Buffet” Model)
Now picture a buffet instead of a sit down server:
- You grab one plate.
- Load it with exactly the foods you want — a little of everything, no more, no less.
- One trip, and you’re good to go.
GraphQL works just like that:
- Single query = one request to fetch multiple fields and types.
- Clients define exactly what they need — no overfetching, no underfetching.
- Your plate holds precisely the data shape your UI expects.
PayPal’s API Evolution
1. The “Chatty REST” Era
Back in the early 2010s, PayPal’s Checkout UI depended on dozens of small REST endpoints:
/user/{id}
for profiles/orders?user={id}
for order history/addresses/{addrId}
for shipping/funding-options/{user}
for payment sources- …and more for experiments, fraud flags, UI config, etc.
Problem: Mobile and web clients were making 10+ HTTP calls just to show one screen. At scale, those 700 ms round trips multiplied into seconds of blank UI, hurting conversion rates and frustrating users.
The Orchestration Band Aid
To mask latency, teams built “orchestration” APIs — endpoints that gathered multiple resources in one response:
GET /checkout/landing-page
Trade offs:
- Clients got everything (even fields they didn’t need).
- Payload sizes ballooned, leading to slower parse times.
- Any new experiment or data requirement forced updates to this monolithic endpoint.
2. The Bulk REST Experiment
Seeking more flexibility, PayPal engineers rolled out a custom Bulk REST service — think of it as your personal waiter who takes a single combined order, then goes to the kitchen once and returns with multiple dishes.
POST /bulk-rest
{
"ops": {
"profile": { "get": "/user/123" },
"orders": { "get": "/orders?user=123" },
"addr": { "get": "/addresses/addr-456", "dependsOn": ["profile"] }
}
}
- Pros:
- Reduced network trips.
- Clients control which endpoints to invoke.
- Cons:
- Developers had to learn a new request DSL.
- Still fetched whole resource objects, not fine grained fields.
- Low adoption — teams found it cumbersome compared to plain REST.
Bulk REST was a clever hack, but it wasn’t the silver bullet PayPal needed.
3. GraphQL to the Rescue
In late 2017, a small PayPal team asked two questions:
- What’s the best way to build data driven front ends in 2018?
- How can we dramatically cut client server chatter?
They prototyped GraphQL for six weeks alongside a new mobile SDK, and the results were so good they went “all in.”
Why GraphQL Won
Criteria | Bulk REST | GraphQL |
---|---|---|
Round trips | 1 per batch of ops | 1 per UI render |
Payload control | Entire resources | Field level precision |
Discoverability | Custom DSL | Introspection + GraphiQL |
Schema evolution | Manual versioning | Built in deprecation |
Developer ramp up | Steep learning | JSON style queries |
- Single hop fetches slashed latency.
- Introspective schema meant UI devs never had to hunt internal docs.
- Parallel work: front end teams could start building UI against the schema before resolvers were production ready.
Within months, PayPal launched a GraphQL + React checkout SDK that:
- Boosted conversions by delivering UI faster.
- Cut iteration time — teams spent 60% less time wiring data.
- Scaled adoption — over 30 teams had rolled out GraphQL services within a year.
Technical Highlights
- Type safe schema. Every field, argument, and return type lives in a central schema, enabling compile time checks in client generators.
- Batching & caching. Under the hood, resolvers leverage DataLoader style batching to prevent N+1 queries against databases or downstream services.
- Auth at the gateway. A GraphQL gateway enforces per field permissions, simplifying downstream services.
- Monitoring & observability. Field usage metrics drive schema pruning — unused fields can be flagged and deprecated gracefully.
Lessons Learned
- Prototype fast. A lean spike delivered clear ROI, easing buy in.
- Design for your use cases. Start with core queries; avoid an all you can eat schema monster.
- Guard performance pitfalls. Watch for deep nesting and resolver fan outs; use caching modules.
- Measure field usage. Schema analytics inform when to remove or optimize parts of your API.
Conclusion
PayPal’s shift from a thousand “waiter trips” to a single “buffet line” is a textbook example of solving both performance and developer experience problems in one go. Even if you’re not building a payment platform, ask yourself:
“Are my clients making too many back and forth requests? Would a GraphQL style ‘buffet’ serve me better than the waiter based REST model?”
If your answer is “yes,” a small GraphQL pilot could transform your API game just like it did for PayPal.