> 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<integer>
```

#### `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<User>

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.

```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<integer>
          page_size: optional<integer>
      response: ListUsersResponse

types:
  ListUsersResponse:
    properties:
      data: list<User>
      has_more: boolean
```

```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<string>
      response: ListUsersResponse

types:
  ListUsersResponse:
    properties:
      data: list<User>
      page:
        properties:
          next:
            properties:
              starting_after: optional<string>
```

```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<Plant>
      next_page_url: optional<string>
```

```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<Plant>
      next_page_path: optional<string>
```

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.

```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<string>
      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
```