> ## Documentation Index
> Fetch the complete documentation index at: https://komga-sdk.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Metadata lookups

> Query genres, tags, authors, publishers, languages, and ratings

Metadata lookup functions return arrays or paginated data. Query parameters are flat generated parameters, and the client is passed in the second options object when parameters are present.

## Genres

```typescript theme={null}
import { getGenres } from 'komga-sdk';

const result = await getGenres(undefined, { client });
if (!result.error) {
  for (const genre of result.data ?? []) console.log(genre);
}
```

Filter by library or collection with the generated `library_id` and `collection_id` keys:

```typescript theme={null}
const libraryGenres = await getGenres(
  { library_id: ['library-123'] },
  { client },
);
const collectionGenres = await getGenres(
  { collection_id: 'collection-123' },
  { client },
);
```

### Filter-key reference

Use the generated names exactly as shown below. The underscore names mirror the wire query keys; `library_id` is an array, while `collection_id`, `series_id`, and `readlist_id` are single IDs:

| Operation(s) | Library | Collection | Other scope |
| - | - | - | - |
| `getGenres`, `getTags`, `getPublishers`, `getLanguages`, `getAgeRatings`, `getSharingLabels` | `library_id?: string[]` | `collection_id?: string` | — |
| `getBookTags` | `library_id?: string[]` | — | `series_id?: string`, `readlist_id?: string` |
| `getSeriesTags` | `library_id?: string` | `collection_id?: string` | — |
| `getAuthors` | `library_id?: string[]` | `collection_id?: string` | `series_id?: string`, `readlist_id?: string` |

Pass `page`, `size`, `sort`, and optionally `unpaged` only to `getAuthors`; the other lookup operations return arrays. Do not translate these names to camelCase (`libraryId` or `collectionId`)—those keys are not part of the generated signatures.

## Tags

The tag endpoints use the same flat filter style, with endpoint-specific keys:

```typescript theme={null}
import { getTags, getBookTags, getSeriesTags } from 'komga-sdk';

const [allTags, bookTags, seriesTags] = await Promise.all([
  getTags({ library_id: ['library-123'] }, { client }),
  getBookTags({ library_id: ['library-123'] }, { client }),
  getSeriesTags({ library_id: 'library-123' }, { client }),
]);

console.log(allTags.data, bookTags.data, seriesTags.data);
```

`getBookTags` also accepts `series_id` and `readlist_id`. `getTags` accepts `collection_id`; `getSeriesTags` accepts `collection_id`.

## Authors

List authors with optional search, role, scope, and pagination parameters:

```typescript theme={null}
import { getAuthors } from 'komga-sdk';

const result = await getAuthors(
  {
    search: 'Toriyama',
    role: 'writer',
    library_id: ['library-123'],
    page: 0,
    size: 50,
  },
  { client },
);

if (!result.error) {
  for (const author of result.data?.content ?? []) {
    console.log(`${author.name} (${author.role})`);
  }
}
```

For autocomplete, use `getAuthorsNames({ search }, { client })`; it returns `string[]`:

```typescript theme={null}
import { getAuthorsNames, getAuthorsRoles } from 'komga-sdk';

const names = await getAuthorsNames({ search: 'Tor' }, { client });
const roles = await getAuthorsRoles({ client });
console.log(names.data, roles.data);
```

## Publishers, languages, ratings, and sharing labels

These endpoints return arrays of strings. `getPublishers`, `getLanguages`, `getAgeRatings`, and `getSharingLabels` accept `library_id?: string[]` and `collection_id?: string`:

```typescript theme={null}
import {
  getPublishers,
  getLanguages,
  getAgeRatings,
  getSharingLabels,
} from 'komga-sdk';

const filters = { library_id: ['library-123'] };
const [publishers, languages, ratings, labels] = await Promise.all([
  getPublishers(filters, { client }),
  getLanguages(filters, { client }),
  getAgeRatings(filters, { client }),
  getSharingLabels(filters, { client }),
]);

console.log({
  publishers: publishers.data ?? [],
  languages: languages.data ?? [],
  ratings: ratings.data ?? [],
  labels: labels.data ?? [],
});
```

Languages use ISO 639-1 codes such as `en`, `ja`, and `fr`.

## Build filter options

Fetch independent lists in parallel and keep each generated result separate so errors remain attributable:

```typescript theme={null}
import {
  getGenres,
  getTags,
  getPublishers,
  getLanguages,
  getAgeRatings,
  getAuthorsRoles,
} from 'komga-sdk';

async function getFilterOptions(libraryId?: string) {
  const filters = libraryId ? { library_id: [libraryId] } : undefined;
  const [genres, tags, publishers, languages, ageRatings, authorRoles] =
    await Promise.all([
      getGenres(filters, { client }),
      getTags(filters, { client }),
      getPublishers(filters, { client }),
      getLanguages(filters, { client }),
      getAgeRatings(filters, { client }),
      getAuthorsRoles({ client }),
    ]);

  return {
    genres: genres.data ?? [],
    tags: tags.data ?? [],
    publishers: publishers.data ?? [],
    languages: languages.data ?? [],
    ageRatings: ageRatings.data ?? [],
    authorRoles: authorRoles.data ?? [],
  };
}
```

## Autocomplete and library summaries

For an autocomplete field, query `getAuthorsNames` rather than loading a full author page. Debounce keystrokes in the UI and avoid sending empty searches:

```typescript theme={null}
import { getAuthorsNames } from 'komga-sdk';

async function searchAuthors(search: string): Promise<string[]> {
  if (search.trim().length < 2) return [];
  const result = await getAuthorsNames({ search }, { client });
  return result.error ? [] : result.data ?? [];
}
```

You can also build a lightweight metadata summary for an administration view. The lookup arrays are complete for the selected scope; authors remain paginated, so use `totalElements` rather than `content.length` for the count:

```typescript theme={null}
import {
  getAuthors,
  getGenres,
  getPublishers,
  getTags,
} from 'komga-sdk';

async function getLibrarySummary(libraryId: string) {
  const filters = { library_id: [libraryId] };
  const [genres, tags, publishers, authors] = await Promise.all([
    getGenres(filters, { client }),
    getTags(filters, { client }),
    getPublishers(filters, { client }),
    getAuthors({ ...filters, page: 0, size: 1 }, { client }),
  ]);

  return {
    genreCount: genres.data?.length ?? 0,
    tagCount: tags.data?.length ?? 0,
    publisherCount: publishers.data?.length ?? 0,
    authorCount: authors.data?.totalElements ?? 0,
  };
}
```

If one request fails, inspect that result's `error` and `response` instead of silently treating every list as empty. Parallel requests improve latency, but they do not make a partial response a successful metadata snapshot.

## Error handling

The default result exposes typed generated errors and the native response. Use the status for transport-level decisions:

```typescript theme={null}
import { getGenres, KomgaApiError, unwrap } from 'komga-sdk';

const result = await getGenres(undefined, { client });
if (result.error) {
  console.error(`Metadata request failed (${result.response?.status})`, result.error);
}

try {
  const genres = unwrap(await getGenres(undefined, { client }));
  console.log(genres);
} catch (error) {
  if (error instanceof KomgaApiError) {
    console.error(error.status, error.body);
  } else {
    throw error;
  }
}
```

## Next steps

> **[Series](/guides/series)**
>
> Filter and search series using metadata.

> **[Books](/guides/books)**
>
> Search books by author, genre, and more.

> **[Collections](/guides/collections)**
>
> Organize content into collections.

> **[Users](/guides/users)**
>
> Configure content restrictions with labels.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.