@storyblok/management-api-client
@storyblok/management-api-client is Storyblok’s modern TypeScript client for the Management API (MAPI). It exposes a single createManagementApiClient() factory that returns resource clients for stories, components, component folders, assets, asset folders, datasources, datasource entries, presets, internal tags, spaces, users, and experiments. Request and response shapes are fully typed and can be narrowed end-to-end by passing a project schema type from @storyblok/schema to .withTypes<Schema>().
Requirements
Section titled “Requirements”- Node.js LTS (version 22.x recommended)
- Modern web browser (the latest versions of Chrome, Edge, Firefox, and Safari) when used in the browser, for example, inside an app extension
Installation
Section titled “Installation”Add the package to a project:
npm install @storyblok/management-api-clientThe following example demonstrates how to initialize the client and list stories in a space:
import { createManagementApiClient } from "@storyblok/management-api-client";
const client = createManagementApiClient({ personalAccessToken: process.env.STORYBLOK_PERSONAL_ACCESS_TOKEN!, spaceId: 12345, region: "eu",});
const { data, error } = await client.stories.list();if (error) throw error;
console.log(data?.stories);Every resource client method returns an ApiResponse object containing data, error, response, and request. Set throwOnError: true on the client (or per request) to receive data directly and have errors thrown as ClientError instances instead.
The following sections document the createManagementApiClient() factory, each resource client, and the exported error class and types.
createManagementApiClient()
Section titled “createManagementApiClient()”Creates a Management API client. Authentication accepts either a personal access token or an OAuth bearer token, never both.
createManagementApiClient(config);The client accepts the following options (the most common are shown here):
| Option | Description |
|---|---|
personalAccessToken |
Required unless oauthToken is provided. Personal access token used for authentication. |
oauthToken |
Required unless personalAccessToken is provided. OAuth bearer token used for authentication. |
spaceId |
Required for space-scoped endpoints. Default space ID; can be overridden per request. |
region |
Region code ('eu', 'us', 'ap', 'ca', 'cn'). Defaults to 'eu'. |
baseUrl |
Overrides the regional base URL (useful for testing). |
headers |
Extra request headers merged into every request. |
throwOnError |
Throws ClientError on HTTP errors instead of returning them. Defaults to false. |
retry |
Retry options. Defaults to up to 12 retries on HTTP 429 with exponential backoff. |
timeout |
Request timeout in milliseconds. Defaults to 30_000. |
rateLimit |
Preventive rate limiting. Defaults to six requests per second. false disables it; a number sets requestsPerSecond; or pass { requestsPerSecond }. |
Per-request space override
Section titled “Per-request space override”Every space-scoped method accepts an optional path: { space_id } override that takes precedence over the client-level spaceId. This allows a single client instance to operate against multiple spaces.
await client.stories.list({ path: { space_id: 67890 } });client.stories
Section titled “client.stories”Use the stories resource client to read, create, update, publish, duplicate, and version stories.
client.stories.list(options?);client.stories.get(storyId, options?);client.stories.create(options);client.stories.update(storyId, options);client.stories.delete(storyId, options?);client.stories.duplicate(storyId, options);client.stories.publish(storyId, options?);client.stories.versions(storyId, options?);storyId is a numeric ID. Pass story content as options.body.story. Use client.stories.versions(storyId) to list the version history of a story.
const { data } = await client.stories.create({ body: { story: { name: "Home", slug: "home", content: { component: "page", title: "Welcome" }, }, },});client.components and client.componentFolders
Section titled “client.components and client.componentFolders”Use the components and componentFolders resource clients to manage block definitions and the folders they belong to.
client.components.list(options?);client.components.get(componentId, options?);client.components.create(options);client.components.update(componentId, options);client.components.delete(componentId, options?);client.components.restore(componentId, options?);client.components.versions(componentId, options?);client.components.version(componentId, versionId, options?);client.components.restoreVersion(componentId, versionId, options?);
client.componentFolders.list(options?);client.componentFolders.get(componentGroupId, options?);client.componentFolders.create(options);client.componentFolders.update(componentGroupId, options);client.componentFolders.delete(componentGroupId, options?);client.assets and client.assetFolders
Section titled “client.assets and client.assetFolders”Use the assets and assetFolders resource clients to upload, read, update, and organize assets and their folders.
client.assets.list(options?);client.assets.get(assetId, options?);client.assets.create(options);client.assets.upload(options);client.assets.update(assetId, options);client.assets.delete(assetId, options?);client.assets.deleteMany(options);client.assets.bulkMove(options);client.assets.bulkRestore(options);client.assets.convertToShared(assetId, options);client.assets.signResponseObject(options);client.assets.finalize(signedResponseObjectId, options?);
client.assetFolders.list(options?);client.assetFolders.get(assetFolderId, options?);client.assetFolders.create(options);client.assetFolders.update(assetFolderId, options);client.assetFolders.delete(assetFolderId, options?);client.assets.upload() performs the full upload flow in one call (sign, upload to S3, finalize) and returns the resulting Asset. client.assets.create() wraps upload() and additionally applies metadata such as alt, title, and copyright in a follow-up update. For the underlying multi-step flow, refer to Upload and replace assets in the Management API reference.
const asset = await client.assets.create({ body: { short_filename: "hero.jpg", asset_folder_id: 0, alt: "Hero image", title: "Homepage hero", }, file: fileBlob,});client.assets.update() accepts an optional file argument: when provided together with a short_filename, the file is replaced first and metadata is updated afterwards in the same call.
Use the lower-level signResponseObject() and finalize() methods only when a custom upload flow is needed (for example, to stream the file from a different process or to integrate with a non-standard storage provider).
deleteMany(), bulkMove(), and bulkRestore() operate on multiple assets in a single request. convertToShared() transfers an asset from the space into the organization’s shared asset library.
The package exports the normalizeAssetUrl() helper for normalizing Storyblok asset URLs across regions.
client.datasources and client.datasourceEntries
Section titled “client.datasources and client.datasourceEntries”Use the datasources and datasourceEntries resource clients to manage datasources and their entries.
client.datasources.list(options?);client.datasources.get(datasourceId, options?);client.datasources.create(options);client.datasources.update(datasourceId, options);client.datasources.replace(datasourceId, options);client.datasources.delete(datasourceId, options?);
client.datasourceEntries.list(options?);client.datasourceEntries.get(datasourceEntryId, options?);client.datasourceEntries.create(options);client.datasourceEntries.update(datasourceEntryId, options);client.datasourceEntries.replace(datasourceEntryId, options);client.datasourceEntries.delete(datasourceEntryId, options?);update() issues a PATCH: only the fields present in the body change. replace() issues a PUT: all updatable fields are replaced.
client.presets
Section titled “client.presets”Use the presets resource client to manage the pre-filled component configurations that editors can choose from in the Visual Editor.
client.presets.list(options?);client.presets.get(presetId, options?);client.presets.create(options);client.presets.update(presetId, options);client.presets.delete(presetId, options?);client.internalTags
Section titled “client.internalTags”Use the internalTags resource client to manage the internal tags that categorize blocks and assets in the Storyblok UI.
client.internalTags.list(options?);client.internalTags.create(options);client.internalTags.update(internalTagId, options);client.internalTags.delete(internalTagId, options?);client.spaces
Section titled “client.spaces”Use the spaces resource client to list and manage spaces.
client.spaces.list(options?);client.spaces.get(options?);client.spaces.create(options);client.spaces.update(options);client.spaces.delete(options?);client.spaces.list() returns every space the authenticated user can access. The other methods operate on the space identified by spaceId.
client.users
Section titled “client.users”Use the users resource client to read and update the authenticated user.
client.users.me(options?);client.users.updateMe(options);me() returns the profile of the authenticated user; updateMe() updates it.
client.experiments
Section titled “client.experiments”Use the experiments resource client to manage experiments and their lifecycle.
client.experiments.list(options?);client.experiments.get(experimentId, options?);client.experiments.create(options);client.experiments.update(experimentId, options);client.experiments.delete(experimentId, options?);client.experiments.activate(experimentId, options?);client.experiments.pause(experimentId, options?);client.experiments.complete(experimentId, options?);client.experiments.completeWithWinner(experimentId, variantId, options?);client.experiments.selectWinner(experimentId, variantId, options?);
client.experiments.stories.create(experimentId, options);client.experiments.stories.delete(experimentId, storyId, options?);
client.experiments.storyMappings.create(experimentId, variantId, options);client.experiments.storyMappings.delete(experimentId, variantId, originalStoryId, options?);
client.experiments.results.get(experimentId, options?);client.experiments.results.push(experimentId, options);The top-level methods cover CRUD plus the state transitions (activate, pause, complete, completeWithWinner, selectWinner). The nested stories and storyMappings resource clients attach stories and variant mappings to an experiment, and results reads or pushes experiment results.
client.sharedAssets, client.sharedAssetFolders, and client.sharedInternalTags
Section titled “client.sharedAssets, client.sharedAssetFolders, and client.sharedInternalTags”Organizations can maintain shared asset libraries: top-level asset folders that several spaces reuse, each with per-space read or write access. Use the sharedAssets, sharedAssetFolders, and sharedInternalTags resource clients to manage them.
client.sharedAssets.list(options?);client.sharedAssets.get(assetId, options?);client.sharedAssets.upload(options);client.sharedAssets.create(options);client.sharedAssets.delete(assetId, options?);
client.sharedAssetFolders.list(options?);client.sharedAssetFolders.get(folderId, options?);client.sharedAssetFolders.create(options);client.sharedAssetFolders.update(folderId, options);client.sharedAssetFolders.delete(folderId, options?);
client.sharedInternalTags.list(options);client.sharedInternalTags.create(options);client.sharedInternalTags.update(tagId, options);client.sharedInternalTags.delete(tagId, options);As with client.assets, sharedAssets.create() runs the full signed-upload flow, while sharedAssets.upload() is the lower-level variant. Each shared asset folder carries per-space access, exposed through the AccessLevel and AssetFolderAccess types.
Escape-hatch HTTP methods and interceptors
Section titled “Escape-hatch HTTP methods and interceptors”For endpoints the resource clients do not yet cover, the client exposes raw HTTP methods that return the same ApiResponse wrapper:
client.get(path, options?);client.post(path, options?);client.put(path, options?);client.patch(path, options?);client.delete(path, options?);The client also exposes client.interceptors, the underlying request and response middleware hooks, for advanced request customization.
ClientError
Section titled “ClientError”Every non-2xx response is wrapped in a ClientError. The error exposes a response property containing status, statusText, and the parsed data from the response body (error.response.status, error.response.statusText, error.response.data). When throwOnError is true, ClientError instances are thrown instead of returned.
throw new ClientError(message, { status, statusText, data });TypeScript
Section titled “TypeScript”@storyblok/management-api-client ships complete type definitions and is fully compatible with @storyblok/schema.
Typed story content
Section titled “Typed story content”Use the client in conjunction with [@storyblok/schema](/docs/libraries/js/schema) to narrow story.content to the project’s component union. The client object exposes a withTypes<T>() method that returns the same instance cast to a version that narrows story content to the components declared in the passed schema. withTypes<T>() accepts either { components: Block } or { blocks: Block }, the latter matches the Schema type produced by @storyblok/schema. It carries no runtime cost and adds no schema values to the bundle.
import { createManagementApiClient } from "@storyblok/management-api-client";import type { Schema } from "./schema";
const client = createManagementApiClient({ personalAccessToken: "your-token", spaceId: 12345,}).withTypes<Schema>();
const { data } = await client.stories.get(42);// data.story.content is now a discriminated union of the schema's blocks.Was this page helpful?
This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.
Get in touch with the Storyblok community