Stack
Stack
A stack holds the content types, entries, and assets of one project. Stack is the object that contentstack.stack() returns, and every other class in the SDK starts from it. Use this class to
- reach content types, entries, assets, global fields, and taxonomies
- retrieve published content in bulk through the Sync API
- set the locale or the live preview state for every later request
Create a Stack with contentstack.stack(). The Contentstack class page lists the options it accepts.
| Name | Type | Description |
|---|---|---|
| apiKey (required) | string | API key of the stack |
| deliveryToken (required) | string | Delivery token to retrieve data from the stack |
| environment (required) | string | Environment name where content is published |
| live_preview | LivePreview | The Live preview configuration for the Contentstack API |
| branch | string | Name of the branch to fetch data from |
| host | string | Sets the host of the API server (example: "dev.contentstack.com") |
| region | string | Region of the stack. You can choose from five regions: NA, EU, Azure NA, Azure EU, GCP NA, and GCP EU. |
| locale | string | Lets you specify which language to use as source content if the entry does not exist in the specified language. |
| cacheOptions.policy | string | Specifies the caching strategy. Accepts a string value from the Policy enum. |
| cacheOptions.storeType | string | Defines where the cache is stored. Accepts localStorage or memoryStorage as string values. |
| cacheOptions.maxAge | number | Sets the maximum age (in milliseconds) before the cache expires. |
| cacheOptions.serializer | function | Function to serialize data before storing it in the cache. |
| cacheOptions.deserializer | function | Function to deserialize data when retrieving it from the cache. |
| early_access | List<string> | Set early access headers |
| logHandler | function | Method to enable custom logging in the SDK |
| plugins | List<any> | Add custom plugins to the SDK |
asset
asset returns an object for one asset when you pass its UID, or a query across every asset in the stack when you do not.
| Name | Type | Description |
|---|---|---|
| uid | string | UID of the asset. Omit it to query all assets. |
Returns: Asset or AssetQuery. A single asset, or a query across the stack's assets.
Validation
- There is no client-side validation. asset hands any non-empty string to the Asset it builds.
- Known issue: In 5.x, an empty string returns an AssetQuery that TypeScript types as Asset, so calling fetch on it throws a TypeError. Check that a UID variable is non-empty before you pass it.
- Passing a string | undefined variable is a compile error, because neither overload accepts undefined.
- Errors that do occur come from the fetch() or find() call on the returned object, not from asset(). That call throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. asset builds an object and makes no request.
- Which class you get back decides which methods are available.
- asset('<ASSET_UID>') returns an Asset, which reads one asset with fetch and shapes the response with methods such as locale and includeDimension. See the Asset class page.
- asset() returns an AssetQuery, which lists assets with find and pages them with limit and skip. See the Asset Collection class page.
- Each call returns a new object. The object shares the stack's HTTP client, so stack-level settings such as locale, branch, and live preview apply to its request.
Example
Basic usage: read one asset by UID
import contentstack from '@contentstack/delivery-sdk';
import type { BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.asset('<ASSET_UID>').fetch<BaseAsset>();
console.log(result.filename, result.url);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}No UID: list the first five assets
import contentstack from '@contentstack/delivery-sdk';
import type { BaseAsset } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
// Omitting the UID returns an AssetQuery, so the terminal call is find.
const result = await stack.asset().limit(5).find<BaseAsset>();
for (const asset of result.assets ?? []) {
console.log(asset.uid, asset.filename);
}
} catch (error: any) {
console.error(error);
}Edge case: an empty UID returns the wrong object
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const assetUid = '';
try {
const result = await stack.asset(assetUid).fetch();
console.log(result);
} catch (error: any) {
// Fires because asset('') returned an AssetQuery, which has no fetch method
console.error('Check the asset UID before calling asset():', error.message);
}contentType
contentType returns an object for one content type when you pass its UID, or a query across every content type in the stack when you do not.
| Name | Type | Description |
|---|---|---|
| uid | string | UID of the content type. Omit it to query all content types. |
Returns: ContentType or ContentTypeQuery. A single content type, or a query across the stack's content types.
Validation
- There is no client-side validation. contentType hands any non-empty string to the ContentType it builds.
- Known issue: In 5.x, an empty string returns a ContentTypeQuery that TypeScript types as ContentType, so calling fetch or entry on it throws a TypeError. Check that a UID variable is non-empty before you pass it.
- Passing a string | undefined variable is a compile error, because neither overload accepts undefined.
- Errors that do occur come from the fetch() or find() call that follows, not from contentType(). That call throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. contentType builds an object and makes no request.
- Which class you get back decides which methods are available.
- contentType('<CONTENT_TYPE_UID>') returns a ContentType, which reads the schema with fetch and reaches the entries with entry. See the ContentType class page.
- contentType() returns a ContentTypeQuery, which lists content types with find and adds global field schemas with includeGlobalFieldSchema. See the ContentType Collection class page.
- Each call returns a new object. The object shares the stack's HTTP client, so stack-level settings such as locale and branch apply to its requests.
Example
Basic usage: read one content type schema
import contentstack from '@contentstack/delivery-sdk';
import type { BaseContentType } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.contentType('<CONTENT_TYPE_UID>').fetch<BaseContentType>();
console.log(result.title, result.schema.length);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Entries: reach the entries of a content type
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.contentType('<CONTENT_TYPE_UID>').entry().limit(3).find();
console.log('entries returned:', result.entries?.length);
} catch (error: any) {
console.error(error);
}No UID: list every content type
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
// Omitting the UID returns a ContentTypeQuery, so the terminal call is find.
const result = await stack.contentType().find();
console.log('content types returned:', result.content_types?.length);
} catch (error: any) {
console.error(error);
}getClient
getClient returns the Axios instance that sends every request from the stack.
Returns: any. The stack's HTTP client.
Validation
- getClient checks nothing and cannot fail. It returns the same instance on every call.
- The return type is any, so TypeScript does not check what you read from or write to the client.
Behavior
- Client-side only. getClient makes no request.
- The instance carries the stack's settings: defaults.baseURL holds the base URL, defaults.headers holds the credential headers, and defaults.params holds the environment and locale query parameters.
- Every object the stack creates sends its requests through this instance. A change you make to it, such as a new interceptor or a default header, applies to every later request from the stack.
- A request you send directly through the instance, such as getClient().get('/content_types'), still passes through the stack's retry handling and plugins, but skips the APIError conversion.
- A failure rejects with the raw Axios error or response body.
- A success resolves with the full Axios response rather than its body.
Example
Basic usage: read the base URL and default parameters
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const client = stack.getClient();
console.log(client.defaults.baseURL); // https://cdn.contentstack.io:443/v3
console.log(client.defaults.params); // { environment: '<ENVIRONMENT>' }Interceptor: time every request the stack sends
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const client = stack.getClient();
client.interceptors.request.use((config: any) => {
config.startedAt = Date.now();
return config;
});
client.interceptors.response.use((response: any) => {
console.log(response.config.url, 'took', Date.now() - response.config.startedAt, 'ms');
return response;
});
try {
const result = await stack.contentType().find();
console.log(result.content_types?.length);
} catch (error: any) {
console.error(error);
}getLastActivities
getLastActivities retrieves the last activity of each content type in the stack's environment.
Returns: Promise<any>. The last-activity response body.
Validation
- There is no client-side validation. getLastActivities takes no input and reads the environment from the stack.
- getLastActivities throws a plain Error when the request fails, for any reason. The SDK replaces the underlying APIError with this generic Error. The caught value has no status, error_code, or error_message, so an invalid token looks the same as a network failure.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Sends one GET /content_types request with the only_last_activity=true and environment query parameters. The stack's locale applies too, when set.
- Returns the response body unchanged and typed as any. The SDK neither unpacks a key nor checks the shape.
- The body holds a content_types array. Each item is a full content type object, with the same keys that stack.contentType().find() returns, including schema. The last_activity object on each item can be empty.
Limitations
- Does not report why a request failed. Send another request on the same stack, such as stack.contentType().limit(1).find(), and read the APIError it throws instead, as the second example shows.
Example
Basic usage: list when each content type last changed
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.getLastActivities();
for (const contentType of result.content_types ?? []) {
console.log(contentType.uid, contentType.last_activity);
}
} catch (error: any) {
// getLastActivities throws a plain Error with no status or error_code
console.error('Request failed:', error.message);
}Error handling: diagnose a failure with a direct request
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.getLastActivities();
console.log(result);
} catch (error: any) {
// The generic Error hides the cause. A content type listing on the same
// stack throws an APIError that carries it.
try {
await stack.contentType().limit(1).find();
console.error('Last activities failed, but the stack answers:', error.message);
} catch (cause: any) {
console.error('Stack request failed:', cause.status, cause.error_code, cause.error_message);
}
}globalField
globalField returns an object for one global field when you pass its UID, or a query across every global field in the stack when you do not.
| Name | Type | Description |
|---|---|---|
| uid | string | UID of the global field. Omit it to query all global fields. |
Returns: GlobalField or GlobalFieldQuery. A single global field, or a query across the stack's global fields.
Validation
- There is no client-side validation. globalField hands any non-empty string to the GlobalField it builds.
- Known issue: In 5.x, an empty string returns a GlobalFieldQuery that TypeScript types as GlobalField, so calling fetch on it throws a TypeError. Check that a UID variable is non-empty before you pass it.
- Passing a string | undefined variable is a compile error, because neither overload accepts undefined.
- Errors that do occur come from the fetch() or find() call that follows, not from globalField(). That call throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. globalField builds an object and makes no request.
- Which class you get back decides which methods are available.
- globalField('<GLOBAL_FIELD_UID>') returns a GlobalField, which reads one global field with fetch.
- globalField() returns a GlobalFieldQuery, which lists global fields with find and pages them with limit and skip.
- Both classes have includeBranch. The Global Fields class page documents both.
- Each call returns a new object. The object shares the stack's HTTP client, so stack-level settings such as branch apply to its request.
Example
Basic usage: read one global field by UID
import contentstack from '@contentstack/delivery-sdk';
interface SeoGlobalField {
uid: string;
title: string;
schema: unknown[];
}
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.globalField('<GLOBAL_FIELD_UID>').fetch<SeoGlobalField>();
console.log(result.title, result.schema.length);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}No UID: list every global field
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
// Omitting the UID returns a GlobalFieldQuery, so the terminal call is find.
const result = await stack.globalField().find();
console.log('global fields returned:', result.global_fields?.length);
} catch (error: any) {
console.error(error);
}livePreviewQuery
livePreviewQuery sets the live preview hash, release, and timestamp that every later request from the stack carries.
| Name | Type | Description |
|---|---|---|
| query.live_preview (required) | string | Preview hash from the Live Preview request. An empty string clears it. |
| query.contentTypeUid | string | UID of the content type in the preview. |
| query.content_type_uid | string | Same as contentTypeUid, in snake_case. |
| query.entryUid | any | UID of the entry in the preview. |
| query.entry_uid | string | Same as entryUid, in snake_case. |
| query.preview_timestamp | string | Point in time to preview content at. |
| query.release_id | string | Release to preview content from. |
| query.include_applied_variants | boolean | The SDK stores it on the config. No request reads it. |
Returns: void. No return value.
Validation
- There is no client-side validation. livePreviewQuery stores the values as given.
- Leaving out live_preview is a compile error, because LivePreviewQuery marks it required. Pass an empty string to clear the hash.
- Errors that do occur come from the next request the stack sends, not from livePreviewQuery().
- When the stack config sets live_preview.enable to true but has no live_preview.host, that request throws an APIError with status 0. The SDK has no preview host to send it to.
- Any other failure throws an APIError carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. livePreviewQuery makes no request.
- When the stack config has live_preview, livePreviewQuery replaces stack.config.live_preview with a copy that holds the new values.
- A non-empty query.live_preview stores the hash, the content type UID, the entry UID, and the timestamp. A missing timestamp becomes an empty string.
- An empty query.live_preview clears the hash, the content type UID, the entry UID, and the timestamp.
- With live_preview.enable set to true and a hash stored, the SDK sends every later request from the stack to live_preview.host, with the hash in the live_preview header. That covers every request, not only the content type and entry you name, so asset and sync requests go to the preview host too.
- release_id and preview_timestamp work even without live_preview in the stack config.
- When query has a release_id key, every later request carries a release_id header. When the key is absent, the SDK removes the header.
- preview_timestamp works the same way, with a preview_timestamp header.
- The SDK stores contentTypeUid, entryUid, and include_applied_variants on the config, but no request reads them.
- Known issue: In 5.x, a server that previews for several users through one shared stack sends one user's preview hash with another user's requests. Create one stack per incoming request when you use live preview on a server.
- Returns void, so you cannot chain a call after it.
Example
Basic usage: preview the entry that the Live Preview request names
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
live_preview: {
enable: true,
preview_token: process.env.CONTENTSTACK_PREVIEW_TOKEN ?? '',
host: 'rest-preview.contentstack.com',
},
});
// In a server, read these from the query string of the incoming page request.
const searchParams = new URLSearchParams(process.env.PREVIEW_QUERY ?? '');
stack.livePreviewQuery({
live_preview: searchParams.get('live_preview') ?? '',
contentTypeUid: searchParams.get('content_type_uid') ?? '',
entryUid: searchParams.get('entry_uid') ?? '',
});
try {
const result = await stack.contentType('<CONTENT_TYPE_UID>').entry('<ENTRY_UID>').fetch();
console.log(result);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}All parameters: preview a release at a point in time
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
live_preview: {
enable: true,
preview_token: process.env.CONTENTSTACK_PREVIEW_TOKEN ?? '',
host: 'rest-preview.contentstack.com',
},
});
// A sample of the query string that Live Preview adds to your page URL.
const searchParams = new URLSearchParams(
'live_preview=a1b2c3d4&content_type_uid=<CONTENT_TYPE_UID>&entry_uid=<ENTRY_UID>' +
'&preview_timestamp=2026-01-01T00:00:00.000Z&release_id=summer_launch',
);
stack.livePreviewQuery({
live_preview: searchParams.get('live_preview') ?? '',
content_type_uid: searchParams.get('content_type_uid') ?? '',
entry_uid: searchParams.get('entry_uid') ?? '',
preview_timestamp: searchParams.get('preview_timestamp') ?? '',
release_id: searchParams.get('release_id') ?? '',
include_applied_variants: true,
});
// The stored preview state, and the headers every later request carries.
console.log(stack.config.live_preview);
console.log(stack.getClient().defaults.headers.release_id, stack.getClient().defaults.headers.preview_timestamp);Edge case: clear the preview state after a preview request
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
live_preview: {
enable: true,
preview_token: process.env.CONTENTSTACK_PREVIEW_TOKEN ?? '',
host: 'rest-preview.contentstack.com',
},
});
// An empty hash, with no release_id or preview_timestamp key, resets every value.
stack.livePreviewQuery({ live_preview: '' });
try {
// This request goes to the delivery host again.
const result = await stack.contentType('<CONTENT_TYPE_UID>').entry().find();
console.log(result.entries?.length);
} catch (error: any) {
console.error(error);
}setDebug
setDebug records the debug flag on stack.config.debug. It has no effect on logging after you create the stack.
| Name | Type | Description |
|---|---|---|
| debug (required) | boolean | Debug flag to record on the config. |
Returns: Stack. The same stack, for chaining.
Validation
- setDebug ignores a value that is not a boolean and returns the stack unchanged, without an error.
- Passing a non-boolean, such as setDebug('true'), is a compile error.
Behavior
- Client-side only. setDebug makes no request.
- Writes the value to stack.config.debug only.
- The SDK installs the debug logging once, inside contentstack.stack(), and only when debug is true there. After that, nothing reads stack.config.debug.
- setDebug(true) on a stack created without debug logs nothing.
- setDebug(false) on a stack created with debug: true keeps logging every request.
Limitations
- Has no effect after you create the stack. Pass debug and logHandler to contentstack.stack() instead, as the second example shows.
Example
Basic usage: record the debug flag on the config
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
stack.setDebug(true);
console.log(stack.config.debug); // true, but the stack logs nothingAlternative: turn on request logging when you create the stack
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
debug: true,
// Required with debug: true. The records include the access_token header.
logHandler: (level: string, data: any) => {
console.log(level, data.type, data.method ?? '', data.url ?? '', data.status ?? '');
},
});
try {
const result = await stack.contentType().find();
console.log(result.content_types?.length);
} catch (error: any) {
console.error(error);
}setLocale
setLocale sets the locale that every later request from the stack sends.
| Name | Type | Description |
|---|---|---|
| locale (required) | string | Locale code, for example fr-fr. |
Returns: void. No return value.
Validation
- There is no client-side validation. setLocale stores an empty string or an unknown locale code as given, and the next request sends it as the locale query parameter.
- The API treats an empty locale as no locale. Entry and asset requests then return the master locale, and sync returns items in every locale.
- Calling setLocale without an argument is a compile error.
- Errors that do occur come from the next request the stack sends, not from setLocale(). That request throws an APIError when it fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. setLocale makes no request.
- Writes the locale into stack.config.locale and into the default query parameters of the stack's HTTP client.
- Every later request from the stack carries the locale, including requests from objects you created before the call, and sync requests.
- A request-level locale wins. An entry or asset that calls its own locale() method sends that value instead.
- Returns void, so you cannot chain a call after it.
Example
Basic usage: read every later request in one locale
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
stack.setLocale('en-us');
try {
const result = await stack.contentType('<CONTENT_TYPE_UID>').entry().find();
console.log(result.entries?.length, 'entries in', stack.config.locale);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: a request-level locale overrides the stack locale
import contentstack from '@contentstack/delivery-sdk';
import type { BaseEntry } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
stack.setLocale('fr-fr');
try {
// This request sends locale=en-us, not fr-fr.
const entry = await stack
.contentType('<CONTENT_TYPE_UID>')
.entry('<ENTRY_UID>')
.locale('en-us')
.fetch<BaseEntry>();
console.log(entry.locale);
} catch (error: any) {
console.error(error);
}setPort
setPort records a port number on stack.config.port. It has no effect on requests after you create the stack.
| Name | Type | Description |
|---|---|---|
| port (required) | number | Port number to record on the config. |
Returns: Stack. The same stack, for chaining.
Validation
- setPort ignores a value that is not a number and returns the stack unchanged, without an error.
- Passing a string, such as setPort('8080'), is a compile error.
- setPort accepts any number, including 0 and negative values.
Behavior
- Client-side only. setPort makes no request.
- Writes the value to stack.config.port only.
- The SDK builds the base URL, including the port, once inside contentstack.stack(). No request reads stack.config.port afterward, so every request keeps the port the stack started with.
Limitations
- Has no effect after you create the stack. Every request keeps the original port, 443 by default. Pass port to contentstack.stack() instead, as the second example shows.
Example
Basic usage: record a port on the config
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
stack.setPort(8443);
console.log(stack.config.port); // 8443
console.log(stack.getClient().defaults.baseURL); // still https://cdn.contentstack.io:443/v3Alternative: set the request port when you create the stack
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
port: 8443,
});
console.log(stack.getClient().defaults.baseURL); // https://cdn.contentstack.io:8443/v3sync
sync retrieves every published entry and asset in one or more pages, and on later calls retrieves only what changed since the previous sync.
| Name | Type | Description |
|---|---|---|
| params | SyncType | SyncStack | Filters for a new sync, or a token to continue one. |
| params.locale | string | Syncs only items in this locale. |
| params.contentTypeUid | string | Syncs only entries of this content type. |
| params.startDate | string | Date filter. The SDK sends it as start_date, which the Sync API does not read. See Limitations. |
| params.type | PublishType[] | PublishType | string | Syncs only these event types. |
| params.environment | string | Environment to sync from. |
| params.paginationToken | string | Token that fetches the next page of a sync. |
| params.syncToken | string | Token that fetches changes since the last sync. |
| recursive | boolean | Follows every pagination token before returning. |
Returns: Promise<SyncResponse>. The sync items, with the token for the next call.
Validation
- There is no client-side validation of the values. An unknown content type UID, locale, or date format reaches the API as given.
- params keys are camelCase. A snake_case key such as sync_token in an object literal is a compile error. In JavaScript, or through a value typed any, sync does not recognize sync_token as a token and starts a new sync instead.
- sync throws an APIError when a request fails, carrying the HTTP status, the API error_code, and the error_message. With recursive set to true, a failure on any page throws and discards the pages already received.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Sends GET /stacks/sync. The stack's environment and locale query parameters apply, and params.environment or params.locale replaces them for that call.
- Starts a new sync when params holds neither a syncToken nor a paginationToken key, by adding init=true to the request.
- Converts each camelCase key to the snake_case query parameter the API reads.
- contentTypeUid becomes content_type_uid, and startDate becomes start_date.
- paginationToken becomes pagination_token, and syncToken becomes sync_token.
- Joins a type array with commas. Accepted PublishType values are entry_published, entry_unpublished, entry_deleted, asset_published, asset_unpublished, asset_deleted, and content_type_deleted.
- With recursive set to false, one call sends one request and returns one page. The response carries pagination_token while more pages remain, and sync_token on the last page.
- With recursive set to true, sync follows each pagination_token and sends one request per page. It returns the last page's response, with the items of every page in its items array. The SDK holds every item in memory until the call returns.
- The response is the raw body typed as SyncResponse: items, and optionally skip, limit, total_count, sync_token, and pagination_token. Each item carries type, event_at, content_type_uid, and data.
- Store the sync_token from the last page. Pass it as params.syncToken on the next call to receive only the changes since.
Limitations
- startDate has no effect. The SDK sends it as start_date, and the Sync API reads the start date only from start_from. A sync with startDate returns the same items as one without it. To filter by date, add a start_from key, as the second example shows. The SDK sends a snake_case key unchanged. For the parameters the Sync API reads, refer to Initial Sync in the Content Delivery API reference.
- Does not resume a recursive sync after a failed page. Leave recursive as false and pass each pagination_token as params.paginationToken yourself, as the third example shows. A failure then costs only the page that failed.
Example
Basic usage: start a sync and read the first page
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.sync();
console.log('items on this page:', result.items.length);
console.log('more pages:', Boolean(result.pagination_token), 'sync token:', result.sync_token);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}All filters: sync published entries of one content type, every page
import contentstack, { PublishType } from '@contentstack/delivery-sdk';
import type { SyncType } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
// The Sync API ignores start_date, the key that startDate becomes. It reads start_from.
const filters: SyncType & { start_from?: string } = {
locale: 'en-us',
contentTypeUid: '<CONTENT_TYPE_UID>',
type: [PublishType.ENTRY_PUBLISHED, PublishType.ENTRY_UNPUBLISHED],
environment: '<ENVIRONMENT>',
start_from: '2024-01-01T00:00:00.000Z',
};
try {
const result = await stack.sync(filters, true);
for (const item of result.items) {
console.log(item.type, item.content_type_uid, item.event_at);
}
console.log('save for the next sync:', result.sync_token);
} catch (error: any) {
console.error(error);
}Pagination token: fetch the next page of a sync
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.sync({ paginationToken: '<PAGINATION_TOKEN>' });
console.log('items on this page:', result.items.length);
} catch (error: any) {
console.error(error);
}Sync token: fetch only the changes since the last sync
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.sync({ syncToken: '<SYNC_TOKEN>' }, true);
for (const item of result.items) {
console.log(item.type, item.data?.uid);
}
console.log('next sync token:', result.sync_token);
} catch (error: any) {
console.error(error);
}taxonomy
taxonomy returns an object for one taxonomy when you pass its UID, or a query across the stack's taxonomies when you do not.
| Name | Type | Description |
|---|---|---|
| uid | string | UID of the taxonomy. Omit it to query taxonomies. |
Returns: Taxonomy or TaxonomyQuery. A single taxonomy, or a query across the stack's taxonomies.
Validation
- There is no client-side validation. taxonomy hands any non-empty string to the Taxonomy it builds.
- Known issue: In 5.x, an empty string returns a TaxonomyQuery that TypeScript types as Taxonomy, so calling fetch on it throws a TypeError. Check that a UID variable is non-empty before you pass it.
- Passing a string | undefined variable is a compile error, because neither overload accepts undefined.
- Errors that do occur come from the fetch() or find() call that follows, not from taxonomy(). That call throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. taxonomy builds an object and makes no request.
- Which class you get back decides which methods are available.
- taxonomy('<TAXONOMY_UID>') returns a Taxonomy, which reads one taxonomy with fetch and reaches its terms with term.
- taxonomy() returns a TaxonomyQuery, whose find lists the published taxonomies of the stack.
- The Taxonomy class page documents both classes.
- Each call returns a new object. The object shares the stack's HTTP client, so stack-level settings such as locale and branch apply to its request.
Example
Basic usage: read one taxonomy by UID
import contentstack from '@contentstack/delivery-sdk';
import type { BaseTaxonomy } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.taxonomy('<TAXONOMY_UID>').fetch<BaseTaxonomy>();
console.log(result.uid, result.name);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}No UID: list the published taxonomies
import contentstack from '@contentstack/delivery-sdk';
import type { BaseTaxonomy } from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
// Omitting the UID returns a TaxonomyQuery, so the terminal call is find.
const result = await stack.taxonomy().find<BaseTaxonomy>();
for (const taxonomy of result.taxonomies ?? []) {
console.log(taxonomy.uid, taxonomy.name);
}
} catch (error: any) {
console.error(error);
}