API Reference
Complete SDK method and type reference
createClient(config)
Creates a content client for fetching models and entries.
import { createClient } from "@better-i18n/sdk";
const client = createClient({
project: "acme/web-app",
apiKey: "bi-your-api-key",
});Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
project | string | Yes | Project identifier in org/project format |
apiKey | string | Yes | API key (prefix: bi-) |
apiBase | string | No | API URL. Default: https://content.better-i18n.com |
debug | boolean | No | Log request URLs and responses to console |
Returns: ContentClient
client.from(modelSlug)
Start a chainable query builder for a content model. This is the primary API for fetching entries.
const builder = client.from("blog-posts"); Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
modelSlug | string | Yes | Content model slug |
Returns: ContentQueryBuilder
The builder is immutable — every chained method returns a new builder instance. The builder is thenable: await it directly to execute a list query.
Query Builder Methods
All methods return a new ContentQueryBuilder instance and can be chained in any order.
| Method | Description |
|---|---|
.select(...fields) | Choose which fields to include in the response |
.eq(field, value) | Filter by field value ("status" or any custom field) |
.filter(field, value) | Filter by custom field value |
.search(term) | Full-text search on entry titles |
.language(code) | Set language code for localized content |
.order(field, opts?) | Set sort field and direction |
.limit(n) | Limit results per page (1–100) |
.page(n) | Set page number (1-based) |
.expand(...fields) | Expand relation fields inline |
.select(...fields)
Choose which fields to include. slug and publishedAt are always returned. When omitted, all fields are returned.
const { data } = await client
.from("blog-posts")
.select("title", "body", "category");| Parameter | Type | Description |
|---|---|---|
...fields | string[] | Field names to include |
.eq(field, value)
Filter entries by exact field value. Works for the built-in status field and any custom field.
const { data } = await client
.from("blog-posts")
.eq("status", "published");| Parameter | Type | Description |
|---|---|---|
field | string | Field name ("status" or custom field name) |
value | string | Value to match |
.filter(field, value)
Filter by a custom field value. Equivalent to .eq() for custom fields.
const { data } = await client
.from("blog-posts")
.filter("category", "engineering");| Parameter | Type | Description |
|---|---|---|
field | string | Custom field name |
value | string | Value to match |
.search(term)
Full-text search on entry titles.
const { data } = await client
.from("blog-posts")
.search("kubernetes");| Parameter | Type | Description |
|---|---|---|
term | string | Search term |
.language(code)
Set the language code for localized content. Falls back to the source language when the requested language has no translation.
const { data } = await client
.from("blog-posts")
.language("fr")
.single("hello-world");| Parameter | Type | Description |
|---|---|---|
code | string | BCP 47 language code (e.g. "en", "fr", "tr") |
.order(field, options?)
Set the sort field and direction.
const { data } = await client
.from("blog-posts")
.order("publishedAt", { ascending: false });| Parameter | Type | Description |
|---|---|---|
field | ContentEntrySortField | "publishedAt", "createdAt", "updatedAt", or "title" |
options.ascending | boolean | true for ascending, false for descending. Default: false |
.limit(n)
Limit the number of entries returned per page.
const { data } = await client.from("blog-posts").limit(20);| Parameter | Type | Description |
|---|---|---|
n | number | Entries per page (1–100). Default: 50 |
.page(n)
Set the page number for pagination (1-based).
const { data } = await client.from("blog-posts").limit(20).page(3);| Parameter | Type | Description |
|---|---|---|
n | number | Page number starting at 1. Default: 1 |
.expand(...fields)
Expand relation fields, resolving referenced entries inline. Expanded relations appear in a relations key on each entry. The relation object's custom fields are flat on the relation object itself.
const { data } = await client
.from("blog-posts")
.expand("author", "category");| Parameter | Type | Description |
|---|---|---|
...fields | string[] | Relation field names to expand |
Terminal Methods
.single<CF>(slug)
Fetch a single entry by slug. Returns a SingleQueryBuilder<CF> which is thenable — await it directly.
const { data: post, error } = await client
.from("blog-posts")
.language("en")
.single("hello-world"); | Parameter | Type | Description |
|---|---|---|
slug | string | Entry slug |
Type Parameter: CF extends Record<string, string | null> — Custom fields shape. Defaults to Record<string, string | null>. See TypeScript guide.
Returns: SingleQueryBuilder<CF> (thenable → SingleQueryResult<ContentEntry<CF>>)
await builder (list query)
Awaiting a ContentQueryBuilder directly executes a list query.
const { data, error, total, hasMore } = await client
.from("blog-posts")
.eq("status", "published");Returns: QueryResult<ContentEntryListItem[]>
Return Types
QueryResult<T>
Returned when awaiting a list query (await client.from(...)).
| Field | Type | Description |
|---|---|---|
data | T | null | Query results, or null on error |
error | Error | null | Error if the request failed, otherwise null |
total | number | Total matching entries across all pages |
hasMore | boolean | Whether more pages exist beyond the current page |
SingleQueryResult<T>
Returned when awaiting a single query (await client.from(...).single(...)).
| Field | Type | Description |
|---|---|---|
data | T | null | Entry data, or null if not found or on error |
error | Error | null | Error if the request failed, otherwise null |
client.getModels()
List all content models in the project.
const models = await client.getModels();Returns: Promise<ContentModel[]>
Legacy Methods
These methods are deprecated. Use from() for all new code. They will be removed in a future major version.
client.getEntries(modelSlug, options?) — deprecated
Use client.from(modelSlug) instead.
// Deprecated
const { items, total, hasMore } = await client.getEntries("blog-posts", {
status: "published",
});
// Preferred
const { data, total, hasMore } = await client
.from("blog-posts")
.eq("status", "published");client.getEntry(modelSlug, entrySlug, options?) — deprecated
Use client.from(modelSlug).single(entrySlug) instead.
// Deprecated
const post = await client.getEntry("blog-posts", "hello-world", {
language: "fr",
});
// Preferred
const { data: post } = await client
.from("blog-posts")
.language("fr")
.single("hello-world");REST API Endpoints
The SDK calls these REST endpoints under the hood:
| Method | Endpoint | SDK |
|---|---|---|
GET | /v1/content/{org}/{project}/models | getModels() |
GET | /v1/content/{org}/{project}/models/{model}/entries | from(model) |
GET | /v1/content/{org}/{project}/models/{model}/entries/{slug} | from(model).single(slug) |
All requests use the x-api-key header for authentication.