An endpoint is a specific URL where an API can be accessed to perform an action on a resource. Thoughtful endpoint design is the foundation of a great developer experience, directly influencing the quality of SDKs and how effectively AI agents can interact with your API in the future.
This guide covers REST endpoint fundamentals, design patterns that scale, and testing strategies that ensure reliability. You’ll learn how proper endpoint structure translates into intuitive SDKs, why consistency matters for both human developers and AI agents, and practical approaches to authentication, error handling, and the emerging Model Context Protocol integration.
An endpoint is a specific URL where an API can be accessed to perform an action on a resource. Thoughtful endpoint design is the foundation of a great developer experience, directly influencing the quality of SDKs and how effectively AI agents can interact with your API in the future.
What are endpoints in REST APIs
In a REST API, an endpoint is a specific URL where a resource lives. Think of your API as a restaurant, the resources as the items on the menu (like "burgers" or "fries"), and an endpoint as the specific instruction to get one of those items, like telling the waiter "I'll have the number 5 burger."
Let's break down a typical API URL: https://api.example.com/v1/users/123
.
The API: The entire system you're talking to, located at the base URL
https://api.example.com/v1
.The Resource: The "noun" or object you're interested in, which in this case is
users
.The Endpoint: The full path that points to a specific user,
/users/123
. It's the combination of the resource and any unique identifiers.
REST principles favor using nouns for resources (/users
) rather than verbs (/getUsers
). The action you want to perform is communicated by the HTTP method, not the URL itself. This structure isn't just academic; it directly translates into how developers interact with your code. A resource like users
naturally maps to a client.users
class in a well-generated SDK, making the code intuitive and predictable. Quality SDK generation ensures these mappings feel natural to developers.
How REST API endpoints work
The interaction with an endpoint follows a simple request-response cycle. A client, like a web browser or a script, sends an HTTP request to an endpoint's URL. The server hosting the API receives this request, and its internal router examines the HTTP method and the path to determine which piece of code should handle it. That code then executes, performs the necessary logic, and sends an HTTP response back to the client.
HTTP methods and purposes
The HTTP method tells the server what action the client wants to perform on the resource at that endpoint. Each method has a distinct purpose.
GET: Retrieves data from a resource. This is a safe operation, meaning it doesn't change any data. It's also idempotent, meaning you can make the same request multiple times and get the same result.
POST: Creates a new resource. For example,
POST /users
would create a new user. This is not idempotent, as calling it multiple times would create multiple new users.PUT: Replaces an existing resource entirely. If you
PUT
data to/users/123
, you're replacing the entire user record with the new data you sent. This is idempotent.PATCH: Partially updates an existing resource. You might use
PATCH
on/users/123
to change only the user's email address without affecting their other details.DELETE: Removes a specific resource. A
DELETE
request to/users/123
would delete that user. This is also idempotent.
Request and response structure
Both the request sent to the endpoint and the response received from it have a defined structure, containing all the information needed for communication.
Path Parameters: These are part of the endpoint's URL and are used to identify a specific resource. In
/users/123
,123
is a path parameter.Query Parameters: These are added to the end of the URL after a
?
and are used to filter, sort, or paginate a collection of resources. For example,/users?status=active
uses a query parameter to fetch only active users.Headers: This is metadata about the request or response. Common request headers include
Authorization
for API keys andContent-Type
to specify the format of the request body (e.g.,application/json
).Body: This contains the data being sent to the server, typically with
POST
,PUT
, orPATCH
requests. It's usually formatted as JSON.Status Codes: Every response includes a three-digit HTTP status code that quickly communicates the outcome. Success is indicated by 2xx codes (like
200 OK
), client-side errors by 4xx codes (404 Not Found
), and server-side errors by 5xx codes (500 Internal Server Error
).
Real-world endpoint examples
Let's look at the GitHub API, which is a great example of clean REST design. To get the issues for a specific repository, you would make a request to:
GET /repos/{owner}/{repo}/issues
This endpoint is clear, hierarchical, and uses nouns. It's easy to understand what resource you're interacting with.
An anti-pattern would be an endpoint like:
GET /retrieveAllRepositoryIssues?owner=stainless-api&repo=stainless-node
This design is less RESTful because it uses a verb (retrieve
) in the path and crams resource identifiers into query parameters instead of the path itself. The first approach is more scalable and easier for developers to predict and use.
Below is how this call might look if you generate a TypeScript SDK using Stainless:
REST endpoint design patterns
Good endpoint design is about consistency and predictability. When developers can guess your endpoints, they can work faster and with fewer errors. Adhering to common patterns is the best way to achieve this.
Use plural nouns: Always use plural nouns for your resources, like
/users
or/products
. This keeps your API consistent, as endpoints will represent either a collection of resources or a single item from that collection.Use nesting for relationships: To represent relationships, nest resources in the URL. For example, to get all the posts for a specific user, an intuitive endpoint would be
/users/{id}/posts
. However, avoid nesting too deeply; more than two levels can make URLs long and unwieldy.Implement versioning in the path: To avoid breaking your users' integrations when you make changes, include a version number in the path, such as
/v1/users
. This allows you to release new versions of your API while maintaining older ones.Support pagination for collections: Endpoints that return a list of items should always be paginated to prevent sending massive amounts of data in a single response. Use query parameters like
limit
andcursor
to let clients request data in manageable chunks.Provide consistent error shapes: When an error occurs, always return a JSON object with a consistent structure. A good practice is
{ "error": { "message": "...", "code": "..." } }
, which makes error handling on the client-side predictable.
Endpoint to SDK mapping
These design patterns have a direct payoff in the developer experience, especially when using an SDK. A paginated endpoint like GET /users?limit=10
doesn't just return data; in a high-quality SDK, it yields an auto-paginating iterator. Your user can simply write a for
loop over client.users.list()
and the SDK handles fetching subsequent pages behind the scenes, abstracting away the complexity of managing cursors and limits.
Similarly, the GitHub issues endpoint from the previous section is exposed via a method like client.repos.listIssuesForRepo()
, making interactions idiomatic, type-safe, and easy to discover.
Authentication patterns
Securing your endpoints is critical. There are several common patterns for authentication, and a good SDK will make using any of them trivial for the developer.
Method | How it Works | Use Case |
---|---|---|
API Key in Header | Client sends a key in a custom header, like | Simple and common for server-to-server communication. |
Bearer Token | Client sends a token in the | The standard for OAuth 2.0, used for user-delegated access. |
Basic Auth | Client sends a base64-encoded username and password in the | Simple but less secure, as credentials are more easily exposed. |
An SDK simplifies this by allowing the developer to instantiate the client with their credentials once, and then automatically adds the correct authorization headers to every subsequent request.
Test REST endpoints
Designing and building endpoints is only half the battle. You need to rigorously test them to ensure they behave as expected, are secure, and perform well under load.
Manual testing workflow
For quick, ad-hoc testing, developers often use command-line tools like cURL
or GUI applications like Postman. These tools allow you to easily construct and send any HTTP request to your endpoints and inspect the full response, including the status code, headers, and body. This is perfect for verifying a new endpoint or debugging a specific issue.
Automated testing workflow
For robust, long-term quality, automated testing is essential. This typically involves writing integration tests that are run as part of a continuous integration (CI) pipeline. These tests start your API server, make requests to the live endpoints, and assert that the responses are correct. You can also perform contract testing, where you validate that your API's responses match the schemas defined in your OpenAPI specification, preventing drift between your documentation and implementation. When creating OpenAPI specs, proper schema definition enables this crucial validation.
SDK testing workflow
A powerful way to write your tests is to use your own generated SDK. Instead of manually constructing HTTP requests and parsing JSON responses in your test code, you can interact with your API through the same type-safe, idiomatic client that your users will have. This not only simplifies the test code but also serves as a great way to "dog-food" your SDK and ensure its developer experience is top-notch. Consider integrating SDK snippets into your documentation to showcase this polished experience.
From REST endpoints to AI agents
Your well-designed REST endpoints are more than just for human developers; they are the perfect foundation for AI agents. The Model Context Protocol (MCP) is an emerging standard that allows Large Language Models (LLMs) to interact with APIs by exposing them as "tools." API to MCP conversion transforms traditional endpoints into AI-accessible interfaces.
The clarity of your endpoint design—its naming, parameters, and structure—is crucial for the LLM to reason about the tool's purpose and use it correctly. Generating an MCP server from an OpenAPI spec is a powerful way to make your API AI-native with minimal effort, opening up new ways for users to interact with your product through natural language.
Frequently asked questions about REST endpoints
What is a REST endpoint example with a real implementation?
A great example is the GitHub API endpoint for listing a user's repositories: GET /users/{username}/repos
. You can call it with cURL 'https://api.github.com/users/stainless-api/repos'
or use an SDK to simply call github.repos.listForUser({ username: 'stainless-api' })
.
How do REST APIs differ from endpoints?
The API is the entire system, including all its endpoints, documentation, and the rules governing their use. An endpoint is just one specific URL within that API that provides access to a particular resource or function.
When should I create a new endpoint versus adding parameters?
Create a new endpoint for a different resource or a distinct relationship (e.g., /users/{id}/posts
). Add query parameters to an existing endpoint to filter, sort, or modify the representation of that endpoint's resource (e.g., /posts?status=published
).
How do REST endpoints handle errors?
They use standard HTTP status codes (like 4xx for client errors and 5xx for server errors) to signal the outcome. They also typically return a JSON body with a consistent error message and an internal error code for easier debugging.
What makes a REST endpoint truly RESTful?
A truly RESTful endpoint adheres to the core constraints of the REST architectural style. This includes being stateless (every request is self-contained), having a clear client-server separation, and using standard HTTP methods to operate on noun-based resources.
Ready to build a world-class developer experience around your API? Get started for free and generate your first SDK in minutes.