API Goals Canvas: Design APIs from the Consumer

Avoid the provider’s-perspective trap, fill an API goals canvas, find missing goals and users, model a booking flow and derive REST resources.

Consumer-first API design: common questions

What is the provider’s perspective in API design?

It is when the API mirrors the provider’s internals, such as table names, internal steps, microservices or team names, instead of what consumers want to do. That makes the API hard to use and turns every internal change into a breaking change.

What is an API goals canvas?

A six-column table: who, what, how, inputs with their source, outputs with their use, and the goal. Following each input to its source and each output to its use reveals missing goals and missing users before any endpoint is written.

Related chapters

Keep learning

Overview

GET /tbl_evt_mstr?evt_nm=coldplay Data leak: the table name and column names of the database. Rename the table and every client breaks. GET /events?query=coldplay&city=mumbai Says what Priya wants: find events. Nothing about where they are stored. Business-logic leak: the client must run the locking steps in the right order. Forget one and a seat is stuck or sold twice. One goal, “hold these seats”. The server does the locking, the timer and the release. GET /inventory-svc/seats + GET /pricing-svc/prices Architecture leak: two internal services are visible, so the app must join seats and prices itself. POST /finance-team/refund-tickets Org-chart leak: the team that handles refunds today. After a reorg the URL lies. POST /bookings/9/cancellation Says what John wants: cancel his booking. Refunds happen behind it. Lab: whose point of view does each endpoint show? Consumer: what they want Provider: how we built it The quick test: could a developer who has never seen our code, database or org chart guess what this endpoint does? And would it survive us renaming a table, splitting a service or moving a team? How (steps) Inputs (source) Outputs (usage) Who uses the API? Start with the main user: a customer like Priya. What does she want to get done? Not “call an endpoint”: buy tickets. How does she do it? Break the what into the steps she takes. What does each step need, and where does it come from? A user, or an earlier step. What does each step give back, and what is it used for next? Rewrite each row as one short goal. These sentences are the API, before any URL exists. Customer (Priya) Buy tickets Search events city, date, text (typed by Priya) matching events (she opens one) Search events by city, date or text See free seats an event (from search) free seats with prices (she picks some) List free seats of an event Hold seats event and seats (from the seat map) a hold that expires in 10 min (pay before then) Hold seats for a short time the hold (previous step), card (Priya, via the payment provider) a booking and e-tickets (shown at the door) Pay for a hold to confirm a booking Lab: fill the goals canvas one column at a time Start over Search needs a city and a date. Where do they come from? Priya types them. The trail ends at a user, so nothing is missing here. Hold needs seat ids. Where do they come from? From “See free seats”, a goal we already have. Nothing missing. Pay returns a booking. How is it used afterwards? Priya wants to find it next week, and maybe cancel it. A missing what: “Manage bookings”, with two goals: list my bookings, cancel a booking. Pay returns e-tickets. How are they used? Gate staff scan them at the venue door. A missing who: venue staff, with the goal “check in a ticket” (and refuse it the second time). The seat map shows events and prices. Where do those come from? Someone creates the event and sets prices: Asha, the venue manager. A missing who with her own whats: publish an event, set prices. Pay needs card details. Do they really come from Priya? She types them into the payment provider’s page, not ours. The provider then tells us the payment went through. A missing who that is a program: the payment provider, with the goal “confirm a payment”. Lab: follow every input back to its source and every output forward to its use Follow it Every trail now ends at a user or at a goal we already have. That is the stop rule.

Start from the consumer: goals, resources and flows

Before choosing a URL or a field name, write down who will call the API and what they are trying to get done. This chapter turns the ticket site into a list of users, goals and one booking flow, and ends with the four things the API is about: Event, Venue, Ticket and Booking.

An API is a control panel

Priya’s app the consumer “Hold seats A1, A2” the API: what she can do Locks, timers, seat rows, services the implementation: hidden The consumer sees buttons and labels. Everything behind them can change without the consumer noticing. A microwave has a panel that says “heat for 2 minutes at medium”. Inside, a part switches on and off in a rhythm to make “medium”, but you never see that. An API is the same kind of panel for software: it shows what a caller can do and hides how it is done. Panel that shows the inside lock seat A1 · lock seat A2 · set status LOCKED · start 10-minute timer · on timeout unlock bothFive steps the app must get right, in order, every time. Panel that shows the goal hold seats A1, A2 for this eventOne step. The server owns the locking, the timer and the clean-up. The left panel is harder to use and also dangerous: an app that crashes between step 2 and step 4 leaves seats locked forever. Hiding the how is what lets you change it later (move locks from the database to Redis, say) without asking any client to change.

The provider’s-perspective trap

Teams that build the system know its insides, so they tend to publish those insides. The leak comes from four places: Table and column names in the URL or payload: tbl_evt_mstr, evt_nm, status codes like 3. Code and rules The client must run internal steps itself: lock, then mark, then release. One missed step breaks your data. One endpoint per microservice, so the client calls three services and joins the answers. Org chart URLs named after teams: /finance-team/…, /growth/…. Teams change more often than users’ needs. The cost is not only ugliness. A leaked table name freezes your schema, since renaming it is now a breaking change ( evolving an API ). Leaked business steps move your rules into a hundred client apps, where you can’t fix them. The gateway can hide your services from callers (proxy, load balancer and gateway (opens in a new tab)), but only if the API wasn’t shaped by them in the first place.

The API goals canvas

A goals canvas is a six-column table you can draw on a whiteboard. You fill it left to right, and each column is one question. Build it for Priya buying tickets: The inputs and outputs columns are the clever part. Writing the source of each input and the use of each output links the rows into a chain, and any link that points nowhere is a goal you forgot. Keep it at this level: no field types, no error codes yet. Those come in the payload chapter

Finding missing goals and all the users

The trail exercise found a missing what for an existing user and three users nobody wrote down. Some users are not found from data at all but from business decisions, like selling through other apps. Here is the full cast for the ticket site: John, Priya Search events, see seats, hold, pay, list and cancel bookings. Venue manager Publish events at her venue, set prices, see sales. Her gate staff check in tickets. Partner app a program A travel app that lists our events and books for its own users, from its own server. support staff Refund disputes, block scalper accounts, fix a broken event. Small group, powerful goals. A “user” here can be a person, a role or a program. Each one adds rows to the canvas, and each one changes what the API must protect: Asha may edit her venue’s events only, which is exactly the ownership check in the security chapter

Who can reach it: visibility and integration type

anyone on the internet Our phone app and website call it. Unknown, huge, spiky traffic (a big concert goes on sale). Must be the most careful about security and change. Partner (community) a known group The travel app and other resellers, each with an API key and a contract. Fewer callers, but each one can demand that an old version keeps running. our own services The booking service calling the seat-inventory service. Few callers you control, so you can change it faster. Not an excuse for a sloppy design. Visibility is a business decision first (who do we sell through, who pays for running it), but it sets technical numbers: expected load, how strong the auth is, and how long old versions must live. A second, separate choice is where the caller sits: Frontend integration A screen calls the backend: Priya’s app filling the seat map. Needs exactly the data one screen shows, paging, fast replies, and care with personal data. Backend integration A server calls a server: the partner’s backend syncing our events every hour, or our booking service calling payments. Needs bulk reads, retries and stable formats more than pretty screens. The two choices mix freely: the partner API is partner-visible and backend-integrated. Write both on the canvas next to each user, since they change the answers in the protocol choice and in network efficiency

API-first: agree on the panel before building the box

Goals canvas who, what, how written API description Mock server fake replies from the contract App and backend built in parallel Build the booking service, then “expose” it. The API ends up shaped like the tables and services that already exist: the trap from section 2. Design the API from the canvas before choosing languages, databases or even URLs. The users’ needs shape it, and both teams start at once. The contracts chapter covers the description format and the tests that keep both sides honest.

Draw the flow: booking as a sequence diagram

Priya’s app Ticket API Payment provider seats A1, A2 search events: Coldplay, Mumbai goal: search events 3 events, Coldplay on 14 Dec show free seats of event 123 goal: list free seats seat map with prices hold A1, A2 goal: hold seats held until 18:40, total ₹9,000 the reply says how long she has held for Priya pay ₹9,000 by card on the provider’s page, not ours payment succeeded for hold h_77 the provider tells our API booking confirmed, e-tickets ready Time runs down. Each arrow is one goal from the canvas, still with no URLs. Drawing the flow checks the canvas. Every arrow must be a goal, and every reply must hold what the caller needs for the next arrow. It also tells the caller whether the step worked. Don Norman’s action cycle describes this: people plan, act, then look at the result to judge if they got what they wanted. A reply of just 200 OK to “hold” leaves Priya’s app unable to show a countdown. The diagram also shows the failure cases you must design for. What if the payment succeeds one second after the hold expired? What if the provider’s message never arrives? Pick an answer now (refund automatically, or extend the hold while a payment is in progress) and write it in the contract. How the provider’s message reaches us is a webhook, covered in polling, SSE and webhooks (opens in a new tab).

From goals to resources and actions

Goals from the canvas, split into an action and the thing it acts on Search events by city, date or text Publish an event at my venue Event at a Venue See a venue’s address and seating plan List free seats of an event, set prices list, update Ticket (one seat at one event, with a price) Check in a ticket at the door change state Hold seats, confirm after payment create, change state Booking (held → confirmed) List my bookings, cancel a booking list, change state Two choices hide in that table. A “hold” did not become its own thing: it is a Booking in the held state with an expiry time, which keeps one object for the whole purchase. And “payment” is not ours: the provider owns it, and our Booking just records its outcome. Fewer things means a smaller, easier API. Coldplay, 14 Dec, 20:00. What people search for. The stadium Asha manages: address, seating plan. Seat A1 at event 123 for ₹4,500: free, held, sold or used. Priya’s purchase of A1 and A2: held, confirmed or cancelled. The names are the ones customers already use, not internal words like “inventory unit” or “order line”. Shared vocabularies help here: schema.org, a public vocabulary for web data, already defines Event and Ticket.

In the interview

Next: giving those four things addresses and verbs, which is what REST is. Spotify’s reference is grouped by what a listener does: search, play, save, build playlists. Read the sidebar as resources

More courses

  • Jobs, linked to lessons — Browse jobs where every requirement links to the chapter that teaches it. See how ready you are, how long the gap takes to close, and which listings look stale.
  • Match a job post to courses — Paste a job post. Each skill is matched to a track here and put in learning order, foundations first.
  • React from open source with patterns — Patterns extracted from Material UI, Radix, React Aria, React Hook Form, Redux Toolkit, TanStack, and Next.js — not slides about hooks.
  • Database in depth — How a query becomes work. Indexes, isolation, locks, and the plans that explain why a page is slow — not an ORM tour.
  • Build a real API with NestJS — One ticket-booking API, built in order: a plain Node server first, then NestJS modules, validation, a real database, and the features real clients lean on.
  • Microservices — Microservice patterns one diagram at a time: how to split a monolith, how services talk, and how data stays consistent without distributed transactions.
  • Kafka — A beginner-to-senior path through event logs, reliable delivery, production operations, and disaster recovery.
  • AI engineering for software engineers — Eight free reads, in order, for software engineers moving into AI: when to build an agent, how to build one, how to test it, and how the model works underneath.
  • Frontend system design — How a UI is sliced when it is a product, not a page: ownership of state, cache, routes, and what happens when the network lies.
  • TypeScript in depth — The type system as a design tool. Inference, narrowing, generics, and the errors that mean the model is wrong — not a catalog of utility types.
  • CSS in depth — See the box, then the page. Visual chapters from the box model through Flexbox surprises, Grid, selectors, and units, then backgrounds, shapes, and visual effects, each with a playground.
  • Accessibility — Foundations first (WCAG in plain words, semantic HTML, lists, alt text), then hands-on HTML labs, a full pass of WAI-ARIA 1.3, and a final fix-the-page challenge.
  • Docker — What an image is, why layers cache, and how containers find each other on a network.
  • Redis — Fifteen Redis patterns, one picture each: cache, session, lock, counter, rate limiter, queue, and when Redis is the wrong tool.
  • Kubernetes — Kubernetes from zero to operators: why it exists, Pods, Deployments and Services, then configuration, networking, storage, scheduling, scaling and security.