> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. # Endpoints in Fern Definition > Organize related API endpoints into a service in Fern Definition and define each endpoint's URL, HTTP method, request, response, errors, and more. Fern Definition isn't recommended for new customers and Fern isn't accepting feature requests for this format. It remains supported for existing users. In Fern, you organize related endpoints into a **Service**. This grouping improves clarity and makes the generated SDKs more idiomatic. ## Service definition Each service defines: 1. A **base-path**: A common prefix for all the endpoints' HTTP paths 2. Whether the service requires [authentication](/learn/api-definitions/ferndef/authentication) 3. **Endpoints** #### user.yml ```yaml service: base-path: /users # This defines the group/namespace for the methods auth: false endpoints: {} ``` To define a service with an empty base path use the empty string: `base-path: ""` ### Section display name By default, section names in your API Reference come from service file names (e.g., `user.yml` becomes "User"). To override the display name of a section, [use the `section` property in your `docs.yml`](/learn/docs/api-references/customize-api-reference-layout#renaming-sections). ### SDK method names SDK method names are derived directly from the service file name and endpoint key. The file name becomes the namespace and the endpoint key becomes the method name. For example, given the following definition: #### users.yml ```yaml service: base-path: /users auth: false endpoints: create: path: "" method: POST request: CreateUserRequest ``` Fern generates a method called `client.users.create()`. ## Endpoints An endpoint includes: * A **URL path** *(Optionally including path parameters)* * A **Display Name** *(Optional)* * An **HTTP Method** * **Request information** *(Optional)* * **Query-parameters** * **Headers** * **Request body** * **Successful (200) response** information *(Optional)* * **Error (non-200) responses** that this endpoint might return *(Optional)* ### URL path Each endpoint has a URL path. #### user.yml ```yaml {6} service: base-path: /users auth: false endpoints: getAllUsers: path: /all method: GET ``` The full path for the endpoint is the concatenation of: * The [environment](/learn/api-definitions/ferndef/api-yml/environments) URL * The service `base-path` * The endpoint `path` ### Endpoint display name The display name will appear as the title of an endpoint. By default, the display name is equal to the 'Title Case' of the endpoint name. If you would like to customize the endpoint name, you can **set the display name**. In the example below, ["Add a new plant to the store"](https://plantstore.dev/api-reference/plant-store-api/plants/add-plant) displays as the title of the endpoint page within the API Reference. #### user.yml ```yaml {7} service: base-path: /v3 auth: false endpoints: addPlant: path: /plant display-name: Add a new plant to the store method: POST ``` ### Path parameters Supply path parameters for your endpoints to create dynamic URLs. #### user.yml ```yaml {6-8} service: base-path: /users auth: false endpoints: getUser: path: /{userId} path-parameters: userId: string method: GET ``` Services can also have path-parameters: #### project.yml ```yaml {2-4} service: base-path: /projects/{projectId} path-parameters: projectId: string auth: false endpoints: ... ``` A path parameter can't share a name with another request property (a body property, query parameter, or header), including after camelCase normalization. `fern check` reports these collisions; set the `name` property on the path parameter to rename it and resolve the collision: #### user.yml ```yaml {4} path-parameters: plantId: type: string name: id ``` ### Query parameters Each endpoint can specify query parameters: #### user.yml ```yaml service: base-path: /users auth: false endpoints: getAllUsers: path: /all method: GET request: # this name is required for idiomatic SDKs name: GetAllUsersRequest query-parameters: limit: optional ``` #### `allow-multiple` Use `allow-multiple` to specify that a query parameter is allowed multiple times in the URL, as in `?filter=jane&filter=smith`. This will alter the generated SDKs so that consumers can provide multiple values for the query parameter. #### user.yml ```yaml {5} ... query-parameters: filter: type: string allow-multiple: true ``` ### Auth Each endpoint can override the auth behavior specified in the service. #### user.yml ```yaml service: base-path: /users auth: false endpoints: getMe: path: "" method: GET # This endpoint will be authed auth: true docs: Return the current user based on Authorization header. ``` ### Headers Each endpoint can specify request headers: #### user.yml ```yaml service: base-path: /users auth: false endpoints: getAllUsers: path: /all method: GET request: # this name is required for idiomatic SDKs name: name: GetAllUsersRequest headers: X-Endpoint-Header: string ``` Services can also specify request headers. These headers will cascade to the service's endpoints. #### user.yml ```yaml {4-5} service: base-path: /users auth: false headers: X-Service-Header: string endpoints: getAllUsers: path: /all method: GET request: # this name is required for idiomatic SDKs name: GetAllUsersRequest headers: X-Endpoint-Header: string ``` ### Request body Endpoints can specify a request body type. #### user.yml ```yaml {10} service: base-path: /users auth: false endpoints: setUserName: path: /{userId}/set-name path-parameters: userId: string method: POST request: string ``` #### Inlining a request body If the request body is an object, you can **inline the type declaration**. This makes the generated SDKs a bit more idiomatic. #### user.yml ```yaml service: base-path: /users auth: false endpoints: createUser: path: /create method: POST request: # this name is required for idiomatic SDKs name: CreateUserRequest body: properties: userName: string ``` ### Success response Endpoints can specify a `response`, which is the type of the body that will be returned on a successful (200) call. #### user.yml ```yaml service: base-path: /users auth: false endpoints: getAllUsers: path: /all method: GET response: list types: User: properties: userId: string name: string ``` ### Response status codes You can also use the `status-code` field to specify a custom status code for a success response. #### user.yml ```yaml {11} service: base-path: /users auth: false endpoints: create: : path: "" method: POST request: CreateUserRequest response: type: User status-code: 201 types: User: properties: userId: string name: string ``` An endpoint has exactly one success response: `response` takes a single type and a single `status-code`. There is no array of success responses. To document a second success body shape, model the response type as a [discriminated or undiscriminated union](/learn/api-definitions/ferndef/types#discriminated-unions), which still renders under one status code. Non-success responses are declared as [errors](/learn/api-definitions/ferndef/errors). ### Pagination Fern supports offset, cursor, URI, and path-based pagination schemes. To set up auto-pagination in [generated SDKs](/learn/sdks/deep-dives/auto-pagination): 1. Annotate the desired paginated endpoint with the `pagination` field 2. Specify the pagination scheme (`offset`, `cursor`, `next_uri`, or `next_path`) 3. Specify where your `results` are located using dot-access notation. #### Offset pagination options Include `step` in most offset pagination configurations to ensure the offset increments by the page size. Use `has-next-page` when your API returns a boolean indicator for additional pages. **`Offset pagination`** ```yaml title="Offset pagination" {8-12} service: base-path: /users auth: false endpoints: list: path: "" method: GET pagination: offset: $request.page step: $request.page_size # Recommended results: $response.data has-next-page: $response.has_more request: name: ListUsersRequest query-parameters: page: optional page_size: optional response: ListUsersResponse types: ListUsersResponse: properties: data: list has_more: boolean ``` **`Cursor pagination`** ```yaml title="Cursor pagination" {8-11} service: base-path: /users auth: false endpoints: list: path: "" method: GET pagination: cursor: $request.starting_after next_cursor: $response.page.next.starting_after results: $response.data request: name: ListUsersRequest query-parameters: starting_after: optional response: ListUsersResponse types: ListUsersResponse: properties: data: list page: properties: next: properties: starting_after: optional ``` **`URI pagination`** ```yaml title="URI pagination" {8-10} service: base-path: /plants auth: false endpoints: list: path: "" method: GET pagination: next_uri: $response.next_page_url results: $response.data response: ListPlantsResponse types: ListPlantsResponse: properties: data: list next_page_url: optional ``` **`Path pagination`** ```yaml title="Path pagination" {8-10} service: base-path: /plants auth: false endpoints: list: path: "" method: GET pagination: next_path: $response.next_page_path results: $response.data response: ListPlantsResponse types: ListPlantsResponse: properties: data: list next_page_path: optional ``` The `pagination` field supports the following properties: | Property | Description | | --------------- | ---------------------------------------------------------------------------------------------- | | `offset` | Path to the offset parameter in the request (e.g., `$request.page`) | | `cursor` | Path to the cursor parameter in the request (e.g., `$request.cursor`) | | `next_cursor` | Path to the next cursor value in the response (required for cursor pagination) | | `next_uri` | Path to the next page's URL in the response (e.g., `$response.next_page_url`) | | `next_path` | Path to the relative path for the next page in the response (e.g., `$response.next_page_path`) | | `results` | Path to the results array in the response (e.g., `$response.data`) | | `step` | Path to the page size parameter, ensures offset increments correctly | | `has-next-page` | Path to a boolean indicator for additional pages | ### Idempotent endpoints Mark an endpoint as idempotent to allow SDK users to specify idempotency headers for safe request retries. You must also configure [idempotency headers in your `api.yml`](/learn/api-definitions/ferndef/api-yml/global-headers#idempotency-headers) to define which headers are available. **`service.yml`** ```yaml title="service.yml" {8} service: base-path: /transactions auth: true endpoints: send: path: "" method: POST idempotent: true request: SendTransactionRequest response: Transaction ``` ### Error responses Endpoints can specify error responses, which detail the non-200 responses that the endpoint might return. #### user.yml ```yaml service: base-path: /users auth: false endpoints: getUser: path: /{userId} path-parameters: userId: string method: GET response: User errors: - UserNotFoundError types: User: properties: userId: string name: string errors: UserNotFoundError: status-code: 404 ``` You can learn more about how to define errors on the [Errors](/learn/api-definitions/ferndef/errors) page. ## Specifying examples When you declare an example, you can also specify some examples of how that endpoint might be used. These are used by the compiler to enhance the generated outputs. Examples will show up as comments in your SDKs, API documentation, and Postman collection. You may add examples for endpoints, types, and errors. #### user.yml ```yaml {13-19} service: base-path: /users auth: false endpoints: getUser: path: /{userId} path-parameters: userId: string method: GET response: User errors: - UserNotFoundError examples: - path-parameters: userId: alice-user-id response: body: userId: alice-user-id name: Alice types: User: properties: userId: string name: string errors: UserNotFoundError: status-code: 404 ``` If you're adding an example to an endpoint and the type already has an example, you can reference it using `$`. ```yaml service: auth: true base-path: /address endpoints: create: method: POST path: "" request: CreateAddress response: Address examples: - request: $CreateAddress.WhiteHouse response: body: $Address.WhiteHouseWithID CreateAddress: properties: street1: string street2: optional city: string state: string postalCode: string country: string isResidential: boolean examples: - name: WhiteHouse value: street1: 1600 Pennsylvania Avenue NW city: Washington DC state: Washington DC postalCode: "20500" country: US isResidential: true Address: extends: CreateAddress properties: id: type: uuid docs: The unique identifier for the address. examples: - name: WhiteHouseWithID value: id: 65ce514c-41e3-11ee-be56-0242ac120002 street1: 1600 Pennsylvania Avenue NW city: Washington DC state: Washington DC postalCode: "20500" country: US isResidential: true ``` Examples contain all the information about the endpoint call, including the request body, path parameters, query parameters, headers, and response body. #### user.yml ```yaml examples: - path-parameters: userId: some-user-id query-parameters: limit: 50 headers: X-My-Header: some-value response: body: response-field: hello ``` #### Failed examples You can also specify examples of failed endpoints calls. Add the `error` property to a response example to designate which failure you're demonstrating. #### user.yml ```yaml {5} examples: - path-parameters: userId: missing-user-id response: error: UserNotFoundError errors: UserNotFoundError: status-code: 404 ``` If the error has a body, then you must include the body in the example. #### user.yml ```yaml {6, 11} examples: - path-parameters: userId: missing-user-id response: error: UserNotFoundError body: "User with id `missing-user-id` was not found" errors: UserNotFoundError: status-code: 404 type: string ``` #### Referencing examples from types To avoid duplication, you can reference examples from types using `$`. #### user.yml ```yaml {12} service: base-path: /users auth: true endpoints: getUser: method: GET path: /{userId} path-parameters: userId: UserId examples: - path-parameters: userId: $UserId.Example1 types: UserId: type: integer examples: - name: Example1 value: user-id-123 ``` > Organize related API endpoints into a service in Fern Definition and define each endpoint's URL, HTTP method, request, response, errors, and more.