Asset Collection

View as Markdown

Asset Collection

AssetQuery lists the published assets in a stack. Use it to read many files in one request, for example to build a media gallery. It shapes every asset in the list the way the Asset class shapes one. To filter the list by a field value, call query first.

Call stack.asset() with no argument to get an AssetQuery.

addParams

addParams adds several query parameters to the asset list request in one call.

NameTypeDescription
paramObj (required){ [key: string]: string | boolean | number }

Parameter names mapped to the values to send.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. addParams accepts an empty object, which changes nothing, and stores any key the API does not recognize as given.
  • Omitting the argument, or passing a value that is not a string, boolean, or number, is a compile error.
  • Errors surface on the find() call that follows, not on addParams(). find() 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. addParams merges the object into the query's parameters and makes no request. find sends them on that call.
  • A key in paramObj overwrites an earlier value under the same key, including one an AssetQuery method wrote. Keys you do not name keep their values.
  • A boolean value goes out as text, so { include_dimension: true } sends include_dimension=true.
  • addParams replaces the query's parameter store with a merged copy. If you created a Query from this AssetQuery with the query method, parameters you set on one object after the call no longer reach the other.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before addParams. See Chain order on the Asset Collection class page.

Example

Basic usage: set paging and a flag together

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack
    .asset()
    .addParams({ include_count: true, limit: 5, skip: 0 })
    .find<BaseAsset>();
  console.log('total:', result.count, 'returned:', result.assets?.length);
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: build the parameters from runtime settings

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

const pageSize = 20;
const withDimensions = true;

const extra: { [key: string]: string | boolean | number } = { limit: pageSize };
if (withDimensions) extra.include_dimension = true;

try {
  const result = await stack.asset().addParams(extra).find<BaseAsset>();
  console.log('returned:', result.assets?.length);
} catch (error: any) {
  console.error(error);
}

assetFields

assetFields adds optional field groups, such as visual markups or user-defined fields, to each asset in the response.

NameTypeDescription
fieldsstring[]

Field group names, one per argument.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. assetFields stores any string, including an empty string or a name the API does not recognize, as given.
  • Passing one array, for example assetFields(['user_defined_fields']), is a compile error, because fields is a rest parameter of strings. Spread an array instead: assetFields(...groups).
  • Errors surface on the find() call that follows, not on assetFields(). find() 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. assetFields sets the asset_fields[] query parameter to the list of names and makes no request. find sends the list on that call.
  • The Content Delivery API accepts two group names, visual_markups and user_defined_fields. The SDK does not check the names, so it also forwards any other name.
  • The API returns the groups only for assets managed in New Assets. An asset stored directly in the stack comes back without the visual_markups and user_defined_fields keys.
  • The groups come in addition to the standard asset fields, such as url, filename, and content_type. They do not filter which assets the list contains.
  • Calling assetFields again with names replaces the earlier list. Calling it with no names leaves the earlier list in place. To clear the list, call the removeParam method with 'asset_fields[]'.
  • The groups are not part of the BaseAsset type, and their shape depends on your stack. Declare them on your own interface, and check each value before you use it.
  • Call assetFields before limit, skip, and the other inherited methods. See Chain order on the Asset Collection class page.

Note The SDK's code comments also name embedded_metadata and ai_generated_metadata. The API rejects both with status 422 and error_code 141, so the request throws an APIError.

Example

Basic usage: list assets with their user-defined fields

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface AssetWithFields extends BaseAsset {
  user_defined_fields?: Record<string, unknown>;
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().assetFields('user_defined_fields').find<AssetWithFields>();
  result.assets?.forEach((asset) => console.log(asset.title, asset.user_defined_fields));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

All parameters: request both field groups on a page of assets

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface AssetWithAllGroups extends BaseAsset {
  user_defined_fields?: Record<string, unknown>;
  visual_markups?: unknown[];
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // assetFields comes before limit, because limit is typed to return Query.
  const result = await stack
    .asset()
    .assetFields('user_defined_fields', 'visual_markups')
    .limit(5)
    .find<AssetWithAllGroups>();
  result.assets?.forEach((asset) => console.log(asset.uid, asset.visual_markups));
} catch (error: any) {
  console.error(error);
}

find

find retrieves the published assets that the query describes.

NameTypeDescription
encodeboolean

URL-encodes string values in the filter conditions.

Default: false

Returns: Promise<FindResponse<T>>. The matching assets.

Validation

  • find checks nothing itself.
  • find throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
  • A network failure also throws an APIError, with status set to 0 and error_code set to the Node error code, for example ENOTFOUND.

Additional Resource Refer to Delivery API Errors for the full error code list.

Behavior

  • Calls GET /assets and makes one HTTP request per call, plus any automatic retries.
  • Sends the environment from the stack config and every value that the chained methods recorded on the query. Calling find twice on one query repeats the same request.
  • Returns the response body as it arrives, not an array. The assets are under the assets key, and count appears when you chain includeCount.
  • The type argument T types each item in assets. The SDK does not check the response against it, and without a type argument each item is unknown.
  • Without limit, the API applies its own page size. See Pagination on the Asset Collection class page for the steps to detect a truncated list.
  • encode applies only to filter conditions in the query request parameter. An AssetQuery has no filter methods, so encode changes nothing unless a Query from the query method added conditions to the shared store. Pass encode to find on that Query instead.

Limitations

  • Does not filter by field value. Use the query method to get a Query, chain a filter, and call find on it.
  • Does not return every asset in one call. Page through the list with skip and limit.

Example

Basic usage: list the published assets

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.uid, asset.filename));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

All parameters: pass encode

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // This query holds no filter conditions, so encode has nothing to encode.
  const result = await stack.asset().includeCount().limit(5).find<BaseAsset>(true);
  console.log('total:', result.count);
} catch (error: any) {
  console.error(error);
}

Typed results with your own interface

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface GalleryImage extends BaseAsset {
  dimension?: { height: number; width: number };
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().includeDimension().limit(12).find<GalleryImage>();
  const images = (result.assets ?? []).filter((asset) => asset.dimension);
  images.forEach((image) => console.log(image.url, image.dimension?.width, image.dimension?.height));
} catch (error: any) {
  console.error(error);
}

includeBranch

includeBranch adds the _branch field to each asset in the response, naming the branch the asset belongs to.

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is nothing to validate. includeBranch takes no arguments and cannot fail.
  • Errors surface on the find() call that follows, not on includeBranch(). find() 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. includeBranch sets include_branch to the string 'true' and makes no request. find sends the flag on that call.
  • includeBranch does not choose a branch. The SDK sends the branch from the stack config as a request header, and without one the API reads the main branch.
  • _branch is not part of the BaseAsset type. Declare it on your own interface to read it without a compile error.

Example

Basic usage: confirm the branch of each listed asset

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface BranchedAsset extends BaseAsset {
  _branch?: string;
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().includeBranch().find<BranchedAsset>();
  result.assets?.forEach((asset) => console.log(asset.title, 'branch:', asset._branch));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

includeCount

includeCount adds the total number of matching assets to the response, as count.

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is nothing to validate. includeCount takes no arguments and cannot fail.
  • Errors surface on the find() call that follows, not on includeCount(). find() 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. includeCount sets include_count to the string 'true' and makes no request. find sends the flag on that call.
  • The API returns count next to the assets array. count is the total across all pages, so it does not change with limit or skip.
  • Compare count with skip plus the number of assets returned to find out whether more pages remain.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before includeCount. See Chain order on the Asset Collection class page.

Example

Basic usage: read the total number of assets

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().includeCount().find<BaseAsset>();
  console.log('total assets:', result.count, 'returned:', result.assets?.length);
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: check whether more pages remain

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

const skip = 0;
const limit = 10;

try {
  const result = await stack.asset().includeCount().skip(skip).limit(limit).find<BaseAsset>();
  const seen = skip + (result.assets?.length ?? 0);
  const total = result.count ?? 0;
  console.log(seen < total ? `${total - seen} more assets to fetch` : 'last page');
} catch (error: any) {
  console.error(error);
}

includeDimension

includeDimension adds the image height and width to each asset in the response, as a dimension object.

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is nothing to validate. includeDimension takes no arguments and cannot fail.
  • Errors surface on the find() call that follows, not on includeDimension(). find() 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. includeDimension sets include_dimension to the string 'true' and makes no request. find sends the flag on that call.
  • The API returns dimension with height and width in pixels for image assets in JPG, GIF, PNG, WebP, BMP, TIFF, SVG, and PSD format. Read dimension as optional, because the API does not promise it for other files in a mixed list.
  • Without includeDimension, the assets in the response have no dimension key.
  • dimension is not part of the BaseAsset type. Declare it on your own interface to read it without a compile error.
  • Call includeDimension before limit, skip, and the other inherited methods. See Chain order on the Asset Collection class page.

Example

Basic usage: list images with their sizes

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface ImageAsset extends BaseAsset {
  dimension?: { height: number; width: number };
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().includeDimension().limit(20).find<ImageAsset>();

  for (const asset of result.assets ?? []) {
    if (asset.dimension) {
      console.log(`${asset.filename}: ${asset.dimension.width}x${asset.dimension.height}`);
    } else {
      console.log(`${asset.filename} (${asset.content_type}) has no dimensions`);
    }
  }
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

includeFallback

includeFallback returns each asset from an earlier locale in the hierarchy when the requested locale has no published version of it.

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is nothing to validate. includeFallback takes no arguments and cannot fail.
  • Errors surface on the find() call that follows, not on includeFallback(). find() 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. includeFallback sets include_fallback to the string 'true' and makes no request. find sends the flag on that call.
  • The flag changes nothing when you request the master locale. Chain the locale method, or set locale in the stack config, to request another locale.
  • The API resolves the fallback for each asset, not the SDK. It returns the version from the nearest earlier locale in the hierarchy that has one published.
  • The response carries no separate fallback flag. Read publish_details.locale on each asset to see the locale the API served.

Example

Basic usage: list French assets, with earlier locales filling the gaps

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().locale('fr-fr').includeFallback().find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.title, 'served in', asset.publish_details?.locale));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

includeMetadata

includeMetadata adds each asset's _metadata object to the response.

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is nothing to validate. includeMetadata takes no arguments and cannot fail.
  • Errors surface on the find() call that follows, not on includeMetadata(). find() 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. includeMetadata sets include_metadata to the string 'true' and makes no request. find sends the flag on that call.
  • _metadata is not part of the BaseAsset type. Declare it on your own interface to read it without a compile error.
  • includeMetadata and the assetFields method write separate request parameters. Setting one does not set the other.

Example

Basic usage: list assets with their metadata

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface AssetWithMetadata extends BaseAsset {
  _metadata?: unknown;
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().includeMetadata().find<AssetWithMetadata>();
  result.assets?.forEach((asset) => console.log(asset.title, asset._metadata));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

limit

limit caps the number of assets the response contains.

NameTypeDescription
key (required)number

Maximum number of assets to return.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. limit stores 0, a negative number, or a decimal as given, and find sends it unchanged.
  • Omitting the argument or passing a string is a compile error, because the parameter type is number.
  • Errors surface on the find() call that follows, not on limit(). find() 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. limit sets the limit query parameter and makes no request. find sends the value on that call.
  • Without limit, find does not return every asset. The API applies its own page size instead. See Pagination on the Asset Collection class page for the steps to detect a truncated list.
  • Calling limit twice replaces the first value. The paginate method of the Pagination class writes the same key, so the later call wins.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before limit. See Chain order on the Asset Collection class page.

Example

Basic usage: return at most ten assets

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().limit(10).find<BaseAsset>();
  console.log('returned', result.assets?.length, 'assets');
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: call asset setters before limit

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface ImageAsset extends BaseAsset {
  dimension?: { height: number; width: number };
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // includeDimension() after limit() would not compile, because limit() declares Query.
  const result = await stack.asset().includeDimension().limit(10).find<ImageAsset>();
  result.assets?.forEach((asset) => console.log(asset.filename, asset.dimension?.width));
} catch (error: any) {
  console.error(error);
}

locale

locale sets the locale the API lists the assets in.

NameTypeDescription
locale (required)string

Locale code to request, for example fr-fr.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. locale accepts an empty string or a code that names no locale and stores it as given.
  • Omitting the argument is a compile error, because locale declares a required string parameter.
  • Errors surface on the find() call that follows, not on locale(). find() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
  • A code that names no locale of the stack fails with status 422, error_code 141, and the message Language was not found. Please try again.

Additional Resource Refer to Delivery API Errors for the full error code list.

Behavior

  • Client-side only. locale sets the locale query parameter and makes no request. find sends the value on that call.
  • The SDK sets no default on the query. Without locale, find sends the locale from the stack config, if you set one there.
  • With no locale at either level, find sends no locale parameter, and the API lists assets in the stack's master locale.
  • A value from locale replaces the stack-level locale for this request only.
  • Calling locale twice replaces the first value. The SDK stores it under a single key.
  • Without fallback, the list holds only the assets published in the requested locale. To include assets that have no published version in that locale, chain the includeFallback method.

Example

Basic usage: list assets in French

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().locale('fr-fr').find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.title, asset.publish_details?.locale));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

orderByAscending

orderByAscending sorts the assets by a field, from the lowest value to the highest.

NameTypeDescription
key (required)string

UID of the field to sort by, for example created_at.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. orderByAscending stores an empty string or a field UID that does not exist as given.
  • Omitting the argument is a compile error, because key is a required string parameter.
  • Errors surface on the find() call that follows, not on orderByAscending(). find() 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. orderByAscending sets the asc query parameter to the field UID and makes no request. find sends the value on that call.
  • Calling orderByAscending twice replaces the first field. The SDK stores it under the single asc key, so one call sorts by one field only.
  • orderByAscending does not clear a desc value from orderByDescending, so both keys go out. When both are present, the API sorts by the desc field and ignores asc. To switch direction, call the removeParam method with 'desc'.
  • The API sorts assets by system fields such as created_at, updated_at, title, and file_size. A field UID that does not exist does not cause an error.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before orderByAscending. See Chain order on the Asset Collection class page.

Example

Basic usage: list the oldest assets first

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().orderByAscending('created_at').limit(10).find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.created_at, asset.title));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: switch a reused query from descending to ascending

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const query = stack.asset().orderByDescending('updated_at');

  // Remove desc first, or both asc and desc go out on the request.
  const result = await query.removeParam('desc').orderByAscending('updated_at').find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.updated_at, asset.title));
} catch (error: any) {
  console.error(error);
}

orderByDescending

orderByDescending sorts the assets by a field, from the highest value to the lowest.

NameTypeDescription
key (required)string

UID of the field to sort by, for example created_at.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. orderByDescending stores an empty string or a field UID that does not exist as given.
  • Omitting the argument is a compile error, because key is a required string parameter.
  • Errors surface on the find() call that follows, not on orderByDescending(). find() 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. orderByDescending sets the desc query parameter to the field UID and makes no request. find sends the value on that call.
  • Calling orderByDescending twice replaces the first field. The SDK stores it under the single desc key, so one call sorts by one field only.
  • orderByDescending does not clear an asc value from orderByAscending, so both keys go out. When both are present, the API sorts by the desc field and ignores asc, so removing asc does not change the order.
  • The API sorts assets by system fields such as created_at, updated_at, title, and file_size. A field UID that does not exist does not cause an error.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before orderByDescending. See Chain order on the Asset Collection class page.

Example

Basic usage: list the newest assets first

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().orderByDescending('created_at').limit(10).find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.created_at, asset.title));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: sort a filtered list

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // query() comes first, then the filter, then the sort.
  const result = await stack
    .asset()
    .query()
    .exists('tags')
    .orderByDescending('updated_at')
    .find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.updated_at, asset.title));
} catch (error: any) {
  console.error(error);
}

param

param adds one query parameter to the asset list request, for a request option that has no method of its own.

NameTypeDescription
key (required)string

Name of the query parameter.

Default: Not applicable
value (required)string | number

Value to send for that parameter.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. param stores an empty key, an empty value, or a key the API does not recognize as given.
  • Passing a boolean, for example param('include_dimension', true), is a compile error, because value accepts only string | number. Pass 'true' instead, or use the addParams method, which accepts booleans.
  • Errors surface on the find() call that follows, not on param(). find() 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. param writes the value under the key and makes no request. find sends it on that call.
  • param overwrites any earlier value under the same key, including a value an AssetQuery method wrote. For example, param('include_count', 'false') after includeCount() sends include_count=false.
  • A key that matches a stack-level parameter replaces it for this request only. param('environment', 'staging') sends environment=staging instead of the environment in the stack config.
  • To remove a key, call the removeParam method.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before param. See Chain order on the Asset Collection class page.

Example

Basic usage: send the include_branch key on a list request

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().param('include_branch', 'true').find<BaseAsset & { _branch?: string }>();
  result.assets?.forEach((asset) => console.log(asset.uid, asset._branch));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

All parameters: a string value and a number value

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // param takes a key and a string or number value.
  const result = await stack
    .asset()
    .param('include_count', 'true')
    .param('limit', 5)
    .find<BaseAsset>();
  console.log('total:', result.count, 'returned:', result.assets?.length);
} catch (error: any) {
  console.error(error);
}

query

query returns a Query that filters the asset list by field values, for example by title or tags.

Returns: Query. A query that filters assets.

Validation

  • There is nothing to validate. query takes no arguments, makes no request, and cannot fail.
  • Errors surface on the find() call of the returned Query, not on query(). That find() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
  • Most Query filter methods accept only letters, digits, underscores, periods, and hyphens in a field UID. For any other UID they log an error with console.error and skip the condition, so the request runs without that filter. The Query class page lists the methods that throw instead.

Additional Resource Refer to Delivery API Errors for the full error code list.

Behavior

  • Returns a new Query whose request path is /assets. The SDK builds it without a content type UID, which selects the assets endpoint instead of an entries endpoint.
  • The Query filter methods, for example where, containedIn, exists, and tags, add conditions to the query request parameter. The Query class page documents each one.
  • The Query shares its parameter store with the AssetQuery that created it:
    • Values you set on the AssetQuery before query(), for example with includeDimension, go out on the Query request.
    • Values you set on the Query also appear on the AssetQuery, so reusing the AssetQuery later sends them too. Start from a fresh stack.asset() for an unrelated request.
    • Calling addParams on either object gives that object a merged copy of the request parameters. After that, parameters you set on one object no longer reach the other, while filter conditions stay shared.
  • The Query has none of the AssetQuery methods. Chain includeDimension, assetFields, locale, and the other asset setters before query().
  • Call query() before limit, skip, and the other inherited methods, because they declare Query as their return type and TypeScript then rejects query(). See Chain order on the Asset Collection class page.
  • find on the returned Query sends GET /assets and returns the response body, with the matching assets under the assets key.

Limitations

  • Does not add filter methods to AssetQuery. A filter such as where called on stack.asset().limit(10) compiles but throws TypeError at runtime. Call query() first, then the filter.

Example

Basic usage: find assets with a given title

import contentstack, { QueryOperation, type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack
    .asset()
    .query()
    .where('title', QueryOperation.EQUALS, 'Logo')
    .find<BaseAsset>();
  console.log('matching assets:', result.assets?.length);
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Asset setters and paging around a filter

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

interface ImageAsset extends BaseAsset {
  dimension?: { height: number; width: number };
}

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack
    .asset()
    .includeDimension() // AssetQuery setter, before query()
    .query()
    .containedIn('tags', ['banner', 'hero']) // Query filter
    .limit(5)
    .find<ImageAsset>();
  result.assets?.forEach((asset) => console.log(asset.title, asset.dimension?.width));
} catch (error: any) {
  console.error(error);
}

Edge case: a filter after an inherited method throws at runtime

import contentstack, { QueryOperation, type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // Compiles, because limit() declares Query as its return type.
  // Throws TypeError, because the object is still an AssetQuery with no where().
  await stack.asset().limit(5).where('title', QueryOperation.EQUALS, 'Logo').find<BaseAsset>();
} catch (error: any) {
  // Fires before any request is sent.
  console.error('Call query() before the filter:', error.message);
}

try {
  // query() first gives a real Query, so the filter works.
  const result = await stack.asset().query().where('title', QueryOperation.EQUALS, 'Logo').limit(5).find<BaseAsset>();
  console.log('matching assets:', result.assets?.length);
} catch (error: any) {
  console.error(error);
}

relativeUrls

relativeUrls adds the relative_url flag to the asset list request.

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is nothing to validate. relativeUrls takes no arguments and cannot fail.
  • Errors surface on the find() call that follows, not on relativeUrls(). find() 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. relativeUrls sets relative_url to the string 'true' and makes no request. find sends the flag on that call.
  • The API ignores the flag. Each asset's url comes back as a full URL with the asset domain, the same as without relativeUrls.
  • To serve assets through your own domain or proxy, read the path from each url with the URL class. Then prefix the path with your host, as the second example shows.
  • To clear the flag, call the removeParam method with 'relative_url', the key this method writes.
  • Call relativeUrls before limit, skip, and the other inherited methods. See Chain order on the Asset Collection class page.

Example

Basic usage: send the flag and read the asset URLs

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().relativeUrls().find<BaseAsset>();
  // Each url still includes the asset domain.
  result.assets?.forEach((asset) => console.log(asset.filename, asset.url));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: serve the assets through your own host

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

// The host that proxies your asset requests.
const assetHost = 'https://assets.example.com';

try {
  const result = await stack.asset().find<BaseAsset>();
  result.assets?.forEach((asset) => {
    // Keep only the path of each asset URL, then put your host in front of it.
    const path = new URL(asset.url).pathname;
    console.log(new URL(path, assetHost).toString());
  });
} catch (error: any) {
  console.error(error);
}

removeParam

removeParam deletes one query parameter from the asset list request.

NameTypeDescription
key (required)string

Request key of the parameter to remove.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. removeParam ignores a key the query does not hold, and the call cannot fail.
  • Omitting the argument is a compile error, because key is a required string parameter.
  • Errors surface on the find() call that follows, not on removeParam(). find() 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. removeParam deletes the key from the query's parameters and makes no request.
  • removeParam takes the request key, not the method name. The keys the AssetQuery methods write are below:
    • include_dimension, include_metadata, include_branch, include_fallback, and include_count
    • relative_url for relativeUrls
    • asset_fields[] for assetFields
    • locale, version, limit, skip, asc, and desc
  • removeParam cannot remove the environment or a stack-level locale. The SDK sends those from the stack config on every request. Override a stack-level value with the param method instead, for example param('locale', 'fr-fr').
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before removeParam. See Chain order on the Asset Collection class page.

Example

Basic usage: drop a flag from a reused query

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const query = stack.asset().includeDimension().includeCount();

  const withDimensions = await query.find<BaseAsset>();
  console.log('total:', withDimensions.count);

  // The same query, now without include_dimension.
  const plain = await query.removeParam('include_dimension').find<BaseAsset>();
  console.log('returned:', plain.assets?.length);
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: clear the field groups from assetFields

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  // assetFields() with no names keeps the earlier list, so remove its key instead.
  const result = await stack
    .asset()
    .assetFields('user_defined_fields')
    .removeParam('asset_fields[]')
    .find<BaseAsset>();
  console.log('returned:', result.assets?.length);
} catch (error: any) {
  console.error(error);
}

skip

skip omits a number of assets from the start of the list, for pagination.

NameTypeDescription
key (required)number

Number of assets to skip from the start of the list.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. skip stores a negative number or a decimal as given, and find sends it unchanged.
  • Omitting the argument or passing a string is a compile error, because the parameter type is number.
  • Errors surface on the find() call that follows, not on skip(). find() 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. skip sets the skip query parameter and makes no request. find sends the value on that call.
  • The SDK sets no default. Without skip, find sends no skip parameter, and the API starts from the first asset.
  • Calling skip twice replaces the first value. The paginate, next, and previous methods of the Pagination class write the same key.
  • Combine skip with limit to read one page at a time. Without a fixed sort order, pages can overlap, so set one with orderByAscending or orderByDescending.
  • TypeScript declares the return type as Query, while the runtime object stays this AssetQuery. Call AssetQuery methods such as includeDimension before skip. See Chain order on the Asset Collection class page.

Example

Basic usage: read the second page of ten assets

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().skip(10).limit(10).find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.title));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}

Edge case: read every page in a loop

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

const pageSize = 50;
const all: BaseAsset[] = [];

try {
  for (let skip = 0; ; skip += pageSize) {
    // A fresh query per page, sorted so that pages do not overlap.
    const page = await stack
      .asset()
      .includeCount()
      .orderByAscending('created_at')
      .skip(skip)
      .limit(pageSize)
      .find<BaseAsset>();
    all.push(...(page.assets ?? []));
    if (!page.assets?.length || all.length >= (page.count ?? 0)) break;
  }
  console.log('read', all.length, 'assets');
} catch (error: any) {
  console.error(error);
}

version

version adds a version number to the asset list request.

NameTypeDescription
version (required)number

Version number to send with the request.

Default: Not applicable

Returns: AssetQuery. The same query, for chaining.

Validation

  • There is no client-side validation. version converts the number to a string and stores it as given.
  • 0, a negative number, a decimal, and NaN all go out unchanged, for example as version=NaN.
  • Passing a string, for example version('2'), is a compile error, because the parameter type is number.
  • Errors surface on the find() call that follows, not on version(). find() 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. version sets the version query parameter to String(version) and makes no request. find sends the value on that call.
  • The SDK sets no default, and it does not filter the list by version itself.
  • The API uses the value as a filter. It returns only the assets whose published version equals the number. A number that no published asset has returns an empty assets array, not an error.
  • With version and no locale, the API returns one entry for each locale where you published the asset. An asset with two published locales appears twice, once per publish_details.locale. Chain the locale method to list one locale only.
  • Calling version twice replaces the first value. The SDK stores it under a single key.
  • Read _version on each returned asset to see the version the API served.

Example

Basic usage: send version 1 with the list request

import contentstack, { type BaseAsset } from '@contentstack/delivery-sdk';

const stack = contentstack.stack({
  apiKey: '<API_KEY>',
  deliveryToken: '<DELIVERY_TOKEN>',
  environment: '<ENVIRONMENT>',
});

try {
  const result = await stack.asset().version(1).find<BaseAsset>();
  result.assets?.forEach((asset) => console.log(asset.filename, 'version', asset._version));
} catch (error: any) {
  // Thrown for API rejections and network failures
  console.error('Request failed:', error.status, error.error_code, error.error_message);
}