How APIs make separate apps feel like one
An API gives software an agreed way to request data or actions. Follow a Sydney trip through GET, POST, permissions, status codes and failure.

Say we’re planning a weekend in Sydney. We add the trip to an app, tap Saturday and a weather forecast appears beside our itinerary. It feels like one app knew both things, even though the people who built the trip planner probably don’t run a weather service as a side project.
The planner and the weather service are separate systems, and somebody has designed a narrow crossing between them. Following the forecast across that crossing and back gives us a useful way of making sense of APIs, because the whole idea lives in the handoff.
That crossing has a name: an application programming interface, or API. It gives one piece of software an agreed way to ask another for information or an action. We can picture it as a deliberately limited opening between two systems, with both sides clear about what can cross and how it should be expressed.
That one forecast gives us a route through the rest of the explanation. As it travels, we can see who is allowed to ask, what the answer looks like to another machine, how failure crosses the boundary and why a small change on one side can break the other. By the time the weather card appears, several decisions have already travelled there and back.
Where the two systems meet
The weather company doesn’t give the trip planner free access to its systems. That would be a bit like cutting a doorway into the office and hoping every visitor only opens the right cupboard. A service window gives us a better shape for the relationship: there’s a known place to ask, a limited set of things on offer and an agreed way to pass the request across.
For this trip, the weather API might allow another app to ask for a forecast by supplying a place and date. It may also allow requests for current conditions and weather warnings, while keeping its forecasting models, raw observations and administrative controls on the other side of the boundary.
The list of supported requests is part of the API’s contract. It tells the trip planner where it can ask, which kinds of request the weather service understands, what details each one needs and what may come back. Documentation records that agreement for the people building on either side.
One request for our trip might be written as GET /forecasts?city=Sydney&day=Saturday. At first it looks like one solid line of code. Pull it apart, though, and every piece has a fairly ordinary job.
The whole /forecasts?city=Sydney&day=Saturday part is the request target. It tells the weather service exactly where this request is headed. Inside it, /forecasts is the path to the forecast endpoint, which is the service window set aside for this job. The details after the question mark are query parameters, which narrow the request to Sydney and Saturday. GET is the method, the standard HTTP word that says the planner wants to retrieve information.
The request may also carry headers with information about the message, such as a credential or the data format the planner can understand. Some requests include a body containing the actual information the service needs to work with. Our simple forecast request can fit its details in the address. A hotel booking needs more room, so its body might hold the dates, guests and room choice together.
At our service window, the endpoint tells us which counter to approach, the method gives the request its verb, the parameters or body carry the details, and the headers carry useful context about the message. The real exchange happens between software, but the comparison helps each technical label stay attached to a job we already recognise.
The two systems can be built by different companies and in different programming languages because neither side needs to understand everything happening inside the other. They only need to honour the part of the agreement that crosses the window.
Then we need a verb
Once the request has somewhere to go, it still needs to say what it wants done there. That’s the job of the method. GET is one of the capital-letter names we keep meeting whenever an API appears in an error message, a product discussion or a search result.
These particular names belong to HTTP, the protocol used by the web and by many APIs. APIs can use other protocols too. So GET and its companions are common API vocabulary, but they aren’t the whole idea of an API.
Our Sydney weekend gives each of the five familiar methods a real job:
- GET says “show us what’s here”. It reads something, such as Saturday’s forecast or an existing hotel reservation. GET is meant to leave that thing unchanged, even though the service may still record that somebody asked for it.
- POST says “here are some details for you to handle”. The planner might POST the information for a new hotel reservation. Creating something is a common result, although POST can ask the service to do other kinds of work too.
- PUT says “make the whole thing at this address look like this”. If the planner stores our complete itinerary at one known address, a PUT can create it or replace the saved version in full.
- PATCH says “change this part of what’s already there”. We might PATCH the itinerary to add a late-arrival note while leaving the train, hotel and restaurant details alone.
- DELETE says “remove what this address currently points to”. It doesn’t promise that the underlying data will be physically erased. The service might delete, archive or deactivate it, so the API’s contract still decides what DELETE means at that endpoint.
There are other methods. HEAD asks for the same response information as GET without sending the response body, and OPTIONS asks what kinds of communication are available at an endpoint. We don’t need to memorise the whole set. Most everyday API conversations become much easier once the first five stop looking like arbitrary capital letters.
Before the window hands anything over
Some APIs are open to anyone. Others give access to private information, cost money to use or allow changes that affect a real person. Before those services hand anything over, they need to know who’s making the request and what they’re allowed to do.
For a weather forecast, the trip planner might send an API key that identifies its account with the weather service. If the request involved our private calendar, the connection might use OAuth so we could give the planner limited permission to read particular information without handing over our calendar password.
This is where two similar words turn up. Authentication checks who is making the request. Authorisation checks what that caller is allowed to do. The weather service can recognise the trip planner perfectly well and still refuse something the planner doesn’t have permission to request.
The distinction matters because an API can offer actions as well as information. A booking service might let the trip planner read a reservation, change it, cancel it or issue a refund, although those actions should not automatically carry the same permission. The method says what kind of action the planner is requesting. The credential and the service’s rules decide whether this caller may request it.
Then something has to come back
The weather service receives our GET request, checks it and sends a response. Its status code gives the short version of what happened. Its body may carry the forecast or explain the problem. Response headers can add useful details around that answer, such as the body’s format or how long the planner may keep a saved copy before asking again.
If the request works, the body may contain a date, temperature range, description and rain probability. The data often comes back as JSON, a text format that can organise information into named fields. The trip planner doesn’t receive the polished card we see. It may receive a field named rain_probability with a value of 0.62, then choose to show a rain icon and 62% chance of rain beside our Saturday plans.
The gap between that raw response and the weather card is easy to miss because the finished screen looks so coherent. The weather service owns the forecast it returns. The trip planner owns how that forecast is explained, where it appears and what we can do next. A technically correct response can still become a confusing product if the app labels it badly, uses the wrong unit or hides an important warning.
Those three digits are the shortest version of the story
Back at our service window, the reply needs a quick signal the planner can recognise before it reads anything else. A status code does that job. It’s one useful result marked on the reply, while the fuller account belongs in the response body.
Status codes arrive as three digits. The first digit places the response in a family, which gives the planner a broad idea of what happened even when it doesn’t recognise the exact code.
- 1xx says the exchange is still in progress. Most of these stay below the surface of an ordinary app experience.
- 2xx says the service successfully received, understood and accepted the request. A
202means the request has been accepted for processing, but the outcome isn’t known yet. The work may still be waiting to start, running or later fail. - 3xx means another step is needed, often because the target has moved or a stored copy can be used.
- 4xx says the service couldn’t fulfil the request because of the request itself, its credentials, the thing being requested or a rule such as a rate limit. These are often called “client errors”, but that doesn’t automatically make them the person’s fault.
- 5xx says the service had a problem while handling a request that looked valid.
The exact number gives the planner a more useful next step. We can keep the Sydney journey beside us while we translate the ones that appear often.
When it works
200 OKcan carry the forecast we asked for.201 Createdcan confirm that a POST or PUT resulted in a new reservation or itinerary.202 Acceptedsays the request has been accepted for processing but hasn’t finished yet.204 No Contentsays the request succeeded without a response body. That could follow a successful note update when the planner doesn’t need the updated note sent back.
When something about the request gets in the way
400 Bad Requestsays the service found a problem with the request and couldn’t or wouldn’t process it.401 Unauthorizedhas a misleading everyday name. In HTTP, it means the request lacks valid authentication credentials for that target.403 Forbiddenmeans the service understood the request and refuses to fulfil it. A recognised account can still lack permission to cancel the reservation.404 Not Foundmeans the service couldn’t find anything at that address, or won’t reveal whether something exists there.405 Method Not Allowedmeans the method is understood but unavailable at this target. Trying to DELETE a forecast endpoint could produce this response.409 Conflictmeans the request clashes with what’s already there. The room or itinerary may have changed since the planner last read it.429 Too Many Requestsmeans the caller has exceeded a request limit for some period. The response may say how long to wait before trying again.
When the service has the problem
500 Internal Server Errorsays something unexpected went wrong inside the service.502 Bad Gatewaysays the service was passing the request along and received an invalid response from another service further along the chain.503 Service Unavailablesays the service can’t handle the request right now, often because it’s overloaded or undergoing maintenance.504 Gateway Timeoutsays the service was passing the request along and didn’t receive a response from another service in time.
That gives us a starting map. We don’t need to learn it by heart. APIs can use other registered codes, and the same code can carry different details in its body. A useful response pairs the number with enough explanation for the planner to work out what should happen next.
If we ask for a forecast beyond the service’s available range, for example, a 4xx response could explain the limit. The planner can then show that message instead of leaving an empty box or exposing a raw number when all we wanted to know was whether to pack a jacket.
A rejected request can still show the API working as designed. The weather service recognised that it couldn’t fulfil this particular request and returned enough information for the planner to choose a path. The planner can still handle that explanation badly, which is one reason the exceptions so often become the job.
What if the booking worked but the answer got lost?
The clearest failure is a response that says what went wrong. A timeout is harder because the planner may stop waiting before it receives an answer. That tells us the reply didn’t arrive in time. It doesn’t tell us whether the booking service created the reservation before the connection failed.
Repeating our weather GET is usually sensible because GET is defined as a safe request: it asks to read the forecast again. Repeating the same hotel-booking POST could create a second reservation if the first request actually worked. Some APIs accept an idempotency key, a unique value that lets the service recognise a retry and keep it attached to the same intended booking.
That concern about whether a repeat changes the outcome has a name: idempotency. A method is idempotent when sending the same request several times has the same intended effect on the server as sending it once. GET and the other safe methods work this way. PUT and DELETE are also idempotent by their intended meaning. POST and PATCH aren’t automatically idempotent, although an API can design particular operations to handle repeats safely.
This changes what the trip planner needs to do after a timeout. It may retry a safe request, check whether the reservation now exists, reuse an idempotency key or ask us before sending another action. “Try again” is a product decision about the method, the consequence and how much the app knows about the first attempt.
The crossing has to stay familiar
The weather company can improve its forecasting models without asking every trip planner to rebuild its app. The planner can redesign the itinerary without asking the weather company to change its response. Both sides can keep working independently as long as the crossing between them still follows the agreement.
Problems begin when one side changes the crossing itself. If the weather service removes the rain field, renames it or changes its meaning, the trip planner may no longer know how to read the answer. If the booking service changes a POST so it needs a new required field, an older planner may start sending requests that can no longer be processed.
Many APIs use versions or other compatibility rules so the old agreement can stay available while callers move to the new one. A change that feels tiny to the provider can break every product still depending on the earlier contract. That’s why changes to endpoints, fields and behaviour need care.
The boundary also makes the dependency easier to see. If the weather service is unavailable, slow or wrong, part of the trip planner is unavailable, slow or wrong. The app may look like one product to us, while its reliability depends on services the planner doesn’t control.
Sometimes the other side speaks first
Our forecast follows a common pattern: the trip planner asks and the weather service answers. Other exchanges begin differently or take longer, which is where a couple of neighbouring ideas become useful.
A payment, for example, may take time to settle. The shop could keep asking whether its status has changed, which is called polling. With a webhook, the shop gives the payment service an address to contact, and the payment service sends an update there when the event happens. The main difference is who starts the exchange.
MCP solves a different problem for AI applications. In an MCP setup, an AI agent can work through tools that its host has made available. MCP gives the host a consistent way to discover and request those tools from an MCP server. The server may then call an ordinary API to reach a calendar, booking system or other service.
The model can choose from the tools it has been given. The host and MCP client carry that request to the server, so the model doesn’t need to learn every external service’s API or call it directly. MCP isn’t the only way to connect an agent system to an API, but it gives that connection a shared structure. It standardises the conversation between the AI application and the MCP server, while an ordinary API may define the server’s connection to the service behind it.
The questions become much more ordinary
Once we understand an API as a boundary with an agreement around it, the useful questions become fairly ordinary:
- What information or action has the other system made available?
- Which endpoint and method match the job?
- Which parameters, headers or body details does the request need?
- Whose identity and permission travel with it?
- Which status codes and response details tell the caller what happened?
- Can this request be repeated safely if the response never arrives?
- Who notices when the agreement changes or one provider starts failing?
- What will the person using the product see when only one part of the chain is unavailable?
We don’t need to write code to take part in those decisions. The answers shape what a product can promise, which organisations it depends on and what happens when a request fails.
Back in the trip planner, the result is still one small weather card beside one Saturday in Sydney. It looks simple because the app has hidden the handoff well. We can now see the journey inside it: an endpoint gave the request somewhere to go, GET said what the planner wanted, parameters narrowed the question, permission travelled with it, and a status code plus a body carried the result home.
The same path can hold a hotel booking, a calendar event or a payment, with different methods and much larger consequences attached. An API is the agreement that lets those separate systems meet. Understanding the journey across that boundary is what lets us ask whether the handoff will still make sense when the request changes, the response fails or one side stops behaving as expected.