> For the complete documentation index, see [llms.txt](https://docs.umbraco.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.umbraco.com/umbraco-cms/19.latest/extend-your-project/backoffice-extensions/foundation/fetching-data/custom-generated-client.md).

# Custom Generated Client

Learn how to create a custom-generated client with TypeScript types for your OpenAPI specification.

A generated client gives you a typed function for each endpoint of your own API. The [`@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) library generates the client from the OpenAPI document of your API. Umbraco generates the [Umbraco HTTP Client](/umbraco-cms/19.latest/extend-your-project/backoffice-extensions/foundation/fetching-data/http-client.md), `umbHttpClient`, with the same library.

Configure your client with `configureClient()`, as described in [Connecting to Umbraco](#connecting-to-umbraco). Your client then handles authentication and the login prompt like `umbHttpClient`. To show a notification from `tryExecute` when a request fails, also set `throwOnError`, as described in the same section.

Generate a client when you call many endpoints of your own API and want types for them. For the Management API, and for a few direct calls to your own API, use `umbHttpClient`.

## Generate your own client

To get started, install the generator using the following command:

```bash
npm install @hey-api/openapi-ts
```

Then, use the `openapi-ts` command to generate a client from your OpenAPI specification:

```bash
npx openapi-ts --input https://example.com/openapi.json --output src/api
```

The command generates a TypeScript client in the `src/api` folder. Import the generated client into your project to make requests to your API.

To learn more about OpenAPI and how to define your API specification, visit the [OpenAPI Documentation](https://swagger.io/specification/).

## Connecting to Umbraco

Your generated client needs the URL of the Umbraco server, and it must send the authentication cookie of the backoffice. Call `configureClient()` on the `UMB_AUTH_CONTEXT` to set up both. The method:

* Sets `baseUrl` to the URL of the Umbraco server.
* Sets `credentials: 'include'`, so the browser sends the authentication cookie with every request. See [Authentication](#authentication).
* Adds the default response interceptors of the backoffice. When a request gets a 401 response, they prompt the user to log in again and then retry `GET` requests. They count successful requests as activity for the session timeout. They also turn error responses into problem details, and show the notifications the server sends in the `Umb-Notifications` header.

{% hint style="info" %}
The [Umbraco Extension Template](/umbraco-cms/19.latest/extend-your-project/backoffice-extensions/development-flow/umbraco-extension-template.md) already includes this setup. If you scaffolded your extension with `dotnet new umbraco-extension`, authentication works out of the box.
{% endhint %}

To show a notification when a request fails, wrap the request in [`tryExecute`](/umbraco-cms/19.latest/extend-your-project/backoffice-extensions/foundation/fetching-data/try-execute.md). A generated client returns failed requests in an `error` property instead of throwing, and `tryExecute` only reports requests that throw. `configureClient()` does not change that. To make your client throw, set `throwOnError` on the `@hey-api/client-fetch` plugin in an `openapi-ts.config.ts` file:

{% code title="openapi-ts.config.ts" %}

```typescript
import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
    input: 'https://example.com/openapi.json',
    output: 'src/api',
    plugins: [
        {
            name: '@hey-api/client-fetch',
            throwOnError: true,
        },
        '@hey-api/typescript',
        '@hey-api/sdk',
    ],
});
```

{% endcode %}

You can also pass `throwOnError: true` to a single SDK function, for example `getMyControllerAction({ throwOnError: true })`.

### Using `configureClient()` (recommended)

Call `configureClient()` from the `onInit` function of a [Backoffice Entry Point](/umbraco-cms/19.latest/extend-your-project/backoffice-extensions/extending-overview/extension-types/backoffice-entry-point.md). An entry point runs once when the backoffice starts, which makes it the place to configure the client.

{% code title="src/entrypoints/entrypoint.ts" %}

```typescript
import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api';
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
import { client } from '../api/client.gen.js';

export const onInit: UmbEntryPointOnInit = async (host) => {
  const authContext = await host.getContext(UMB_AUTH_CONTEXT);
  if (!authContext) {
    console.warn('UMB_AUTH_CONTEXT is not available, so the API client is not configured');
    return;
  }

  // Sets the base URL and credentials, and adds the default interceptors
  authContext.configureClient(client);
};
```

{% endcode %}

The `client` export comes from the `client.gen.ts` file that `@hey-api/openapi-ts` generates next to your SDK functions. `configureClient()` accepts any client generated by `@hey-api/openapi-ts`. Calling the method again for the same client has no effect.

{% hint style="warning" %}
Copying the configuration of `umbHttpClient` into your client copies settings but not interceptors. The `runtimeConfigPath` option of `@hey-api/openapi-ts` is one way to do that. A request that gets a 401 response then fails instead of prompting the user to log in again. Use `configureClient()` instead.
{% endhint %}

### Passing `umbHttpClient` directly

If you only have a few requests, you can skip client configuration entirely and pass `umbHttpClient` as the `client` parameter on each call. In an element that extends `UmbLitElement`:

{% code title="my-element.ts" %}

```typescript
import { getMyControllerAction } from './api/index.js';
import { tryExecute } from '@umbraco-cms/backoffice/resources';
import { umbHttpClient } from '@umbraco-cms/backoffice/http-client';

const { data } = await tryExecute(this, getMyControllerAction({
    client: umbHttpClient,
}));

if (data) {
    console.log('Data:', data);
}
```

{% endcode %}

The example above uses the backoffice HTTP client directly instead of the generated client. The `umbHttpClient` already has authentication and the correct base URL configured.

## Authentication

The backoffice session is an HTTP-only authentication cookie. The browser sends the cookie with every request that uses `credentials: 'include'`, and scripts in the browser cannot read it. There is no access token to request, attach to a request, or refresh.

The cookie also authenticates your own API controllers when they use the backoffice authorization policies. For an example, see [Custom Backoffice API](/umbraco-cms/19.latest/extend-your-project/server-side-extensions/custom-backoffice-api.md).

{% hint style="info" %}
In Umbraco 17 and 18, the client sent a bearer token that it got from the `auth` callback. Umbraco 19 removes `getLatestToken()` from the `UMB_AUTH_CONTEXT`, and `configureClient()` no longer sets an `auth` callback. Remove any code that adds an `Authorization` header to backoffice requests.
{% endhint %}

### Expired sessions in your own controllers

When the session has expired, the server answers a request to an API controller with a 401 response. The interceptors of the backoffice then prompt the user to log in again. For your own controllers, the server answers with a 401 when the controller has the `[ApiController]` attribute. Controllers that inherit from `ManagementApiControllerBase` already have it, and so does the base controller in the Umbraco Extension Template. Without the attribute, the server redirects the request to the login page instead.

{% hint style="info" %}
The redirect is what you want for endpoints that people open directly in the browser rather than call from the backoffice. Examples are a link to a file download or a page that is shared by URL. Leave out `[ApiController]` on those controllers. To keep the redirect for a single action in an `[ApiController]` controller, add the `[AllowCookieRedirect]` attribute from `Microsoft.AspNetCore.Http` to the action.
{% endhint %}

### Security requirements in the OpenAPI document

Generated SDK functions can include `security` metadata from your OpenAPI document. The backoffice does not use the metadata, so you do not need to pass `security` when you call `umbHttpClient` directly.

The security requirements still matter to Swagger UI and to [API Users](/umbraco-cms/19.latest/manage-and-publish-content/users-and-members/users/api-users.md), which authenticate with access tokens. Umbraco adds the requirements to the Management API automatically. If you expose a separate API with its own OpenAPI document, call `AddBackofficeSecurityRequirements()` on the `OpenApiOptions` passed into `AddOpenApi`:

{% code title="MyExtensionApiComposer.cs" %}

```csharp
using Umbraco.Cms.Api.Management.OpenApi;

builder.Services.AddOpenApi("myextension", options =>
{
    // ...other configuration

    options.AddBackofficeSecurityRequirements();
});
```

{% endcode %}

The method registers the security scheme and adds the requirement to each operation, skipping any operation marked with `[AllowAnonymous]`.

If you register the document with `AddBackOfficeOpenApiDocument()`, as the Umbraco Extension Template does, call `WithBackOfficeAuthentication()` on the document instead. It calls `AddBackofficeSecurityRequirements()` for you.

For a complete walkthrough of setting up a custom API, see [Creating a Backoffice API](/umbraco-cms/19.latest/extend-your-project/tutorials/creating-a-backoffice-api.md), [Custom Backoffice API](/umbraco-cms/19.latest/extend-your-project/server-side-extensions/custom-backoffice-api.md), and [API versioning and OpenAPI](/umbraco-cms/19.latest/extend-your-project/server-side-extensions/api-versioning-and-openapi.md).

## Further reading

* [@hey-api/openapi-ts](https://heyapi.dev/openapi-ts/get-started)
* [Creating a Backoffice API](/umbraco-cms/19.latest/extend-your-project/tutorials/creating-a-backoffice-api.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.umbraco.com/umbraco-cms/19.latest/extend-your-project/backoffice-extensions/foundation/fetching-data/custom-generated-client.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
