@reflag/management-sdk
v0.0.4
Published
Reflag Management SDK
Downloads
186
Readme
@reflag/management-sdk (beta)
Typed SDK for interacting with Reflag’s Management API.
Use @reflag/management-sdk to programmatically manage feature flags such as listing flags, and enabling or disabling them for specific users or companies.
For a practical example of what you can build, see the Customer Admin Panel example app.
Installation
npm i @reflag/management-sdk
# or
yarn add @reflag/management-sdkCreate a client
Initialize the SDK with a Reflag Management API Key.
import { Api } from "@reflag/management-sdk";
const api = new Api({
accessToken: process.env.REFLAG_API_KEY,
});API surface
Main exports:
Api: base clientcreateAppClient(appId, config): app-scoped clientReflagApiError: normalized API error type- Generated request/response types and models from
@reflag/management-sdk
Core method groups:
- Applications:
listApps,getApp - Environments:
listEnvironments,getEnvironment - Flags:
listFlags,createFlag,updateFlag - User/company evaluation:
getUserFlags,updateUserFlags,getCompanyFlags,updateCompanyFlags
Quick start
const apps = await api.listApps();
console.log(apps.data);
// [
// {
// "org": { "id": "org-1", "name": "Acme Org" },
// "id": "app-123",
// "name": "Acme App",
// "demo": false,
// "flagKeyFormat": "kebabCaseLower",
// "environments": [
// { "id": "env-123", "name": "Development", "isProduction": false, "order": 0 },
// { "id": "env-456", "name": "Production", "isProduction": true, "order": 1 }
// ]
// }
// ]
const app = apps.data[0];
const appId = app?.id;
if (appId) {
const environments = await api.listEnvironments({
appId,
sortBy: "order",
sortOrder: "asc",
});
console.log(environments.data);
// [
// { "id": "env-456", "name": "Production", "isProduction": true, "order": 1 }
// ]
}App-scoped client
If most calls are for one app, use createAppClient to avoid repeating appId.
import { createAppClient } from "@reflag/management-sdk";
const appApi = createAppClient("app-123", {
accessToken: process.env.REFLAG_API_KEY,
});
const environments = await appApi.listEnvironments({
sortBy: "order",
sortOrder: "asc",
});
console.log(environments.data);
// [
// { "id": "env-456", "name": "Production", "isProduction": true, "order": 1 }
// ]
const flags = await appApi.listFlags({});
console.log(flags.data);
// [
// {
// "id": "flag-1",
// "key": "new-checkout",
// "name": "New checkout",
// "description": "Rollout for redesigned checkout flow",
// "stage": { "id": "stage-1", "name": "Beta", "color": "#4f46e5", "order": 2 },
// "owner": {
// "id": "user-99",
// "name": "Jane Doe",
// "email": "[email protected]",
// "avatarUrl": "https://example.com/avatar.png"
// },
// "archived": false,
// "stale": false,
// "permanent": false,
// "createdAt": "2026-03-03T09:00:00.000Z",
// "lastCheckAt": "2026-03-03T09:30:00.000Z",
// "lastTrackAt": "2026-03-03T09:31:00.000Z"
// }
// ]Common workflows
Create and update a flag
createFlag and updateFlag return { flag } with the latest flag details.
Use null to clear nullable fields like description or ownerUserId on update.
const created = await api.createFlag({
appId: "app-123",
key: "new-checkout",
name: "New checkout",
description: "Rollout for redesigned checkout flow",
secret: false,
});
const updated = await api.updateFlag({
appId: "app-123",
flagId: created.flag.id,
name: "New checkout experience",
ownerUserId: null,
});
console.log(updated.flag);
// {
// "id": "flag-1",
// "key": "new-checkout",
// "name": "New checkout experience",
// "description": "Rollout for redesigned checkout flow",
// "stage": { "id": "stage-1", "name": "Beta", "color": "#4f46e5", "order": 2 },
// "owner": {
// "id": "user-99",
// "name": "Jane Doe",
// "email": "[email protected]",
// "avatarUrl": "https://example.com/avatar.png"
// },
// "archived": false,
// "stale": false,
// "permanent": false,
// "createdAt": "2026-03-03T09:00:00.000Z",
// "lastCheckAt": "2026-03-03T09:35:00.000Z",
// "lastTrackAt": "2026-03-03T09:36:00.000Z",
// "rolledOutToEveryoneAt": "2026-03-10T12:00:00.000Z",
// "parentFlagId": "flag-parent-1"
// }Read user flags for an environment
getUserFlags evaluates flag results for one user in one environment and returns
the user’s current values plus exposure/check metadata for each flag.
const userFlags = await api.getUserFlags({
appId: "app-123",
envId: "env-456",
userId: "user-1",
});
console.log(userFlags.data);
// [
// {
// "id": "flag-1",
// "key": "new-checkout",
// "name": "New checkout",
// "createdAt": "2026-03-03T09:00:00.000Z",
// "value": true,
// "specificTargetValue": true,
// "firstExposureAt": "2026-03-03T09:05:00.000Z",
// "lastExposureAt": "2026-03-03T09:30:00.000Z",
// "lastCheckAt": "2026-03-03T09:31:00.000Z",
// "exposureCount": 12,
// "firstTrackAt": "2026-03-03T09:06:00.000Z",
// "lastTrackAt": "2026-03-03T09:32:00.000Z",
// "trackCount": 5
// }
// ]Toggle a user flag
Use true to explicitly target on, and null to remove specific targeting.
const updatedUserFlags = await api.updateUserFlags({
appId: "app-123",
envId: "env-456",
userId: "user-1",
updates: [{ flagKey: "new-checkout", specificTargetValue: true }],
});
console.log(updatedUserFlags.data);
// [
// {
// "id": "flag-1",
// "key": "new-checkout",
// "name": "New checkout",
// "createdAt": "2026-03-03T09:00:00.000Z",
// "value": true,
// "specificTargetValue": true,
// "firstExposureAt": "2026-03-03T09:05:00.000Z",
// "lastExposureAt": "2026-03-03T09:35:00.000Z",
// "lastCheckAt": "2026-03-03T09:36:00.000Z",
// "exposureCount": 13,
// "firstTrackAt": "2026-03-03T09:06:00.000Z",
// "lastTrackAt": "2026-03-03T09:37:00.000Z",
// "trackCount": 6
// }
// ]Read company flags for an environment
const companyFlags = await api.getCompanyFlags({
appId: "app-123",
envId: "env-456",
companyId: "company-1",
});
console.log(companyFlags.data);
// [
// {
// "id": "flag-1",
// "key": "new-checkout",
// "name": "New checkout",
// "createdAt": "2026-03-03T09:00:00.000Z",
// "value": false,
// "specificTargetValue": null,
// "firstExposureAt": null,
// "lastExposureAt": null,
// "lastCheckAt": "2026-03-03T09:31:00.000Z",
// "exposureCount": 0,
// "firstTrackAt": null,
// "lastTrackAt": null,
// "trackCount": 0
// }
// ]Toggle a company flag
Use true to explicitly target on, and null to remove specific targeting.
const updatedCompanyFlags = await api.updateCompanyFlags({
appId: "app-123",
envId: "env-456",
companyId: "company-1",
// Use `null` to stop targeting the company specifically for that flag.
updates: [{ flagKey: "new-checkout", specificTargetValue: null }],
});
console.log(updatedCompanyFlags.data);
// [
// {
// "id": "flag-1",
// "key": "new-checkout",
// "name": "New checkout",
// "createdAt": "2026-03-03T09:00:00.000Z",
// "value": false,
// "specificTargetValue": null,
// "firstExposureAt": null,
// "lastExposureAt": null,
// "lastCheckAt": "2026-03-03T09:36:00.000Z",
// "exposureCount": 0,
// "firstTrackAt": null,
// "lastTrackAt": null,
// "trackCount": 0
// }
// ]Error handling
The SDK throws ReflagApiError for non-2xx API responses.
import { ReflagApiError } from "@reflag/management-sdk";
try {
await api.listApps();
} catch (error) {
if (error instanceof ReflagApiError) {
console.error(error.status, error.code, error.message, error.details);
}
throw error;
}Example app
See packages/management-sdk/examples/customer-admin-panel/README.md for a small Next.js app using this SDK in server actions.
License
MIT
