Better I18NBetter I18N

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:

FieldTypeRequiredDescription
projectstringYesProject identifier in org/project format
apiKeystringYesAPI key (prefix: bi-)
apiBasestringNoAPI URL. Default: https://content.better-i18n.com
debugbooleanNoLog 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:

ParameterTypeRequiredDescription
modelSlugstringYesContent 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.

MethodDescription
.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");
ParameterTypeDescription
...fieldsstring[]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");
ParameterTypeDescription
fieldstringField name ("status" or custom field name)
valuestringValue 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");
ParameterTypeDescription
fieldstringCustom field name
valuestringValue to match

.search(term)

Full-text search on entry titles.

const { data } = await client
  .from("blog-posts")
  .search("kubernetes");
ParameterTypeDescription
termstringSearch 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");
ParameterTypeDescription
codestringBCP 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 });
ParameterTypeDescription
fieldContentEntrySortField"publishedAt", "createdAt", "updatedAt", or "title"
options.ascendingbooleantrue 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);
ParameterTypeDescription
nnumberEntries 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);
ParameterTypeDescription
nnumberPage 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");
ParameterTypeDescription
...fieldsstring[]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"); 
ParameterTypeDescription
slugstringEntry 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(...)).

FieldTypeDescription
dataT | nullQuery results, or null on error
errorError | nullError if the request failed, otherwise null
totalnumberTotal matching entries across all pages
hasMorebooleanWhether more pages exist beyond the current page

SingleQueryResult<T>

Returned when awaiting a single query (await client.from(...).single(...)).

FieldTypeDescription
dataT | nullEntry data, or null if not found or on error
errorError | nullError 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:

MethodEndpointSDK
GET/v1/content/{org}/{project}/modelsgetModels()
GET/v1/content/{org}/{project}/models/{model}/entriesfrom(model)
GET/v1/content/{org}/{project}/models/{model}/entries/{slug}from(model).single(slug)

All requests use the x-api-key header for authentication.


Types

On this page