On this page

The six steps

Step 1: Requirements before endpoints

Step 2: Find the resources

Step 3: Write the endpoints

Step 4: Shape the requests and responses

Step 5: Design the failures

Step 6: Handle change

Pagination, filtering, and sorting

Authentication and authorisation

Make writes safe to retry

A checklist before you publish

Frequently asked questions

Keep going

Related Reading

How to Design a RESTful API: Resources, Methods, and Status Codes

Image
Arslan Ahmad
A step by step guide to designing a REST API: model resources, pick HTTP methods, shape requests and responses, handle errors, paginate, and version safely.
Image

The six steps

Step 1: Requirements before endpoints

Step 2: Find the resources

Step 3: Write the endpoints

Step 4: Shape the requests and responses

Step 5: Design the failures

Step 6: Handle change

Pagination, filtering, and sorting

Authentication and authorisation

Make writes safe to retry

A checklist before you publish

Frequently asked questions

Keep going

Related Reading

To design a RESTful API, work in one order every time. Find the resources, then write the endpoints. Shape the requests and responses next. Then handle errors, pagination, versioning, and authentication. Endpoints are the middle of the job, not the start.

A RESTful API is a web API where things get URLs, HTTP methods act on them, and each request carries everything the server needs. This guide takes a single example, an order service, from a blank page to a contract you could publish.

The six steps

StepQuestion it answersOutput
1. RequirementsWho calls this, and to do what?A short list of operations
2. ResourcesWhat are the nouns?Resource names and relationships
3. EndpointsHow do callers act on them?Paths and methods
4. PayloadsWhat goes in and out?Request and response shapes
5. FailureWhat happens when things go wrong?Status codes and error bodies
6. ChangeHow does this survive next year?Versioning and deprecation

Step 1: Requirements before endpoints

Two questions decide most of the design.

Who calls it? A public API used by outside developers needs stability, clear docs, and a deprecation policy. An internal API between two services you own can change next week. Do not pay the public price for an internal API.

What are the operations, in plain words? Write them as sentences before you write any paths. For an order service: place an order, look one up, list a customer's orders, cancel one, and get its shipment status.

That list is short on purpose. Five clear operations produce a better API than twenty guessed endpoints.

Step 2: Find the resources

A resource is a noun worth addressing. Take the operations and pull out the things.

From the list above: orders, customers, and shipments. Cancel is not a resource. It is a change to an order.

Then decide how they relate. A shipment belongs to an order. An order belongs to a customer. Ownership becomes a path, and independent things get their own top level path.

A useful test: if you can imagine fetching it on its own, it is a resource. If it only makes sense inside something else, it is a sub resource or a field.

Step 3: Write the endpoints

Now the paths. Collections are plural nouns. Actions are HTTP methods, never words in the path.

POST   /v1/orders                     Place an order
GET    /v1/orders/{id}                Read one order
GET    /v1/customers/{id}/orders      List a customer's orders
POST   /v1/orders/{id}/cancel         Cancel an order
GET    /v1/orders/{id}/shipment       Shipment status

Two decisions in there are worth defending in an interview.

Why /customers/{id}/orders and not /orders?customer_id={id}? Both work. The nested path is clearer when the list only makes sense in that context. The query parameter is better when you also filter by other things, because you can combine them. Many APIs offer both.

Why is cancel a sub path rather than a method? Cancelling is a state change with rules attached, and it is not a plain field update. When an action does not map cleanly onto create, replace, or delete, a named sub resource is the honest option. Keep those rare. If half your paths end in verbs, the resource model is wrong.

Step 4: Shape the requests and responses

The request carries only what the caller can know. The server fills in the rest.

POST /v1/orders { "customer_id": "cus_8123", "items": [ { "sku": "DG-1001", "quantity": 2 } ], "shipping_address_id": "addr_55" }

The client does not send the order id, the status, or the total. Those are the server's to decide. A field the client can set that it should not be able to set is a bug waiting to happen.

201 Created Location: /v1/orders/ord_9f2 { "id": "ord_9f2", "status": "pending", "customer_id": "cus_8123", "items": [ { "sku": "DG-1001", "quantity": 2, "unit_price": 1299 } ], "total": 2598, "currency": "USD", "created_at": "2026-08-10T09:14:22Z" }

Four habits make responses easy to live with. Return the created resource, so the client does not need a second call. Send money as an integer in the smallest unit, because floating point rounding on currency causes real bugs. Use one date format everywhere, ISO 8601 with a timezone. Keep field naming identical across every endpoint.

Step 5: Design the failures

Most of an API's quality lives in what happens when things go wrong.

Pick the status code first.

  • 400 the request was malformed.
  • 401 we do not know the caller.
  • 403 we do know, and the answer is no.
  • 404 nothing is there.
  • 409 a conflict, such as cancelling an order that already shipped.
  • 422 the syntax was fine but the values were not.
  • 429 too many requests.

Then return a body a program can read.

{ "error": { "code": "order_already_shipped", "message": "This order has shipped and can no longer be cancelled.", "request_id": "req_01H8XK2N" } }

The code is part of the contract, so it must stay stable once clients branch on it. The message is for humans and can be reworded. The request id is what a support engineer will ask for.

Never return 200 with an error inside. Every monitor, retry rule, and cache reads the status code.

Step 6: Handle change

An API is used far longer than it takes to build. Some callers will never update.

Version only when a change would break a working client. Removing a field, renaming one, changing its type, or making an optional input required are all breaking. Adding an optional field or a new endpoint is not.

Put the major version in the path, /v1/, so it is visible in logs and a gateway can route on it. Publish how long an old version lives, and announce the end date in the traffic with Deprecation and Sunset headers, not only by email.

Ask clients to ignore fields they do not recognise. That one habit removes most of the pressure to cut a new version at all.

Pagination, filtering, and sorting

Any endpoint that returns a list needs a limit from day one.

GET /v1/customers/{id}/orders?limit=20&cursor=eyJpZCI6OTkxfQ&status=shipped&sort=-created_at

Pagination. Offset pagination takes a page number and gets slower the deeper you go, because the database reads and discards skipped rows. Cursor pagination takes a pointer to the last item, stays fast at any depth, and does not repeat rows when new ones arrive. Use cursor for lists that grow, offset for small stable ones.

Filtering. Keep filters as query parameters named after the fields they filter. ?status=shipped is guessable. ?f=1 is not.

Sorting. One parameter, with a minus sign for descending. ?sort=-created_at is a common convention and easy to document.

Cap the page size, document the cap, and return the cap rather than an error when someone asks for more.

Authentication and authorisation

Authentication is who you are. Authorisation is what you may do. They fail differently, which is why 401 and 403 are separate codes.

Use HTTPS for everything, with no plain HTTP fallback. Use OAuth 2.0 when you act on a user's behalf, and scoped tokens so a read only client cannot write. Never accept credentials in a query string, because query strings end up in server logs and browser history.

Check authorisation on the server for every request. A client that hides a button has not protected anything.

Make writes safe to retry

A phone on a weak connection sends the same order twice. The first request worked, the response was lost, the app retried.

Accept an idempotency key on writes. The client generates a unique value and sends it as a header. The server stores the key with the result, and returns that stored result if the key arrives again.

POST /v1/orders
Idempotency-Key: 8f14e45f-ea6a-4c1b-9f2b-2a1d4f3c9b77

GET, PUT, and DELETE are already idempotent by definition. POST is the one that needs the key.

A checklist before you publish

  • Every collection endpoint has a page size cap.
  • Every write that creates something accepts an idempotency key.
  • Every error returns a stable code, not just a sentence.
  • Field naming and date formats are identical across endpoints.
  • The version is in the path and the gateway routes on it.
  • Rate limits are returned in headers, not only in the docs.
  • The schema is the source of truth and the docs are generated from it.
  • A developer who has seen two endpoints can guess the third.

Frequently asked questions

How do you design a RESTful API?

Work in order. Gather requirements, find the resources, then write endpoints as plural nouns with HTTP methods. Shape requests and responses, then design errors, pagination, versioning, and auth. Resources come before endpoints, and failure design comes before polish.

What is the difference between REST and RESTful?

REST is the architectural style. RESTful describes an API that follows it. In practice most APIs called RESTful follow the useful parts, such as resources, methods, and statelessness, and skip the strictest constraint, hypermedia.

Should REST endpoints be singular or plural?

Plural for collections, so /orders and /orders/42. The reason is consistency rather than grammar. Once a developer sees the pattern once, they can predict every other path.

How many endpoints should a REST API have?

As few as the operations require. Start from the list of things callers need to do, and resist adding an endpoint per screen. A screen specific endpoint becomes dead weight the moment the screen changes.

What makes an API RESTful rather than just HTTP?

Resources with stable URLs, HTTP methods used for their real meaning, statelessness so any server can handle any request, and consistent representations. Using HTTP to post to /doAction is HTTP, not REST.

How do I design a REST API for a system design interview?

Say the six steps out loud as you go. Interviewers grade the order and the trade offs more than the exact paths. Name idempotency, pagination, and versioning before you are asked, because those three are the follow up questions.

Keep going

Designing the contract is a skill you can practise directly. Grokking Modern API Design Interview teaches this same six step method. It applies the method to 15 complete designs, including payment, chat, booking, and file storage APIs.

For the wider round, Grokking the System Design Interview covers the caching, sharding, and replication that sit underneath a real API.

API
System Design Fundamentals
System Design Interview

What our users say

KAUSHIK JONNADULA

Thanks for a great resource! You guys are a lifesaver. I struggled a lot in design interviews, and Grokking System Design gave me an organized process to handle a design problem. Please keep adding more questions.

Simon Barker

This is what I love about http://designgurus.io’s Grokking the coding interview course. They teach patterns rather than solutions.

ABHISHEK GUPTA

My offer from the top tech company would not have been possible without Grokking System Design. Many thanks!!

More From Designgurus
Annual Subscription
Get instant access to all current and upcoming courses for one year.

Access to 50+ courses

New content added monthly

Certificate of completion

$31.08

/month

Billed Annually

Recommended Course
Grokking the Object Oriented Design Interview

Grokking the Object Oriented Design Interview

60,269+ students

4.2

Learn how to prepare for object oriented design interviews and practice common object oriented design interview questions. Master low level design interview.

View Course
Join our Newsletter

Get the latest system design articles and interview tips delivered to your inbox.

Read More

Complete Load Balancer Guide 2026

Arslan Ahmad

Arslan Ahmad

Grokking Webhooks: Stop Polling, Start Pushing Data Like a Pro

Arslan Ahmad

Arslan Ahmad

What Is Grokking the System Design Interview? A Complete Guide

Arslan Ahmad

Arslan Ahmad

Mastering the System Design Interview: A Complete Guide

Arslan Ahmad

Arslan Ahmad

Design Gurus logo
One-Stop Portal For Tech Interviews.
Copyright © 2026 Design Gurus, LLC. All rights reserved.