Integrations

Admin API

Manage projects, environments, configs, targeting rules, segments, and tags over HTTPS with an API token. The base URL, authentication, permissions, error responses, usage counting, the endpoints, and the OpenAPI document.

Introduction

The Admin API is the HTTPS interface to everything you manage in the dashboard for a project: projects, environments, configs and their targeting rules, segments, and tags. The Terraform provider and the MCP server are built on it, and anything they can do, a script of yours can do too.

Every request goes through the same validations as the dashboard, so a value that the dashboard would refuse is refused here with the same message. Every change shows in the audit log with a source of API and the name of the token that made it.

The API describes itself with an OpenAPI 3.1 document, which needs no authentication:

https://api.configdirector.com/v1/openapi.json

It holds the exact request and response schema of every endpoint on this page, including the targeting rule and segment condition shapes, and the base URL below as its server, so it is the file to hand to an OpenAPI client generator.

Base URL

https://api.configdirector.com/v1

Requests and responses are JSON. Send Content-Type: application/json with every request that has a body. Projects, environments, and tags are addressed by their id, a UUID; configs and segments are addressed by their key, so a URL reads the way the dashboard does:

GET https://api.configdirector.com/v1/projects/{projectId}/configs/new-checkout

Authentication

Create an API token in the dashboard under API tokens and send it as a bearer token:

Authorization: Bearer YOUR-API-TOKEN

A token belongs to the member who created it, and only that member can see, rename, or revoke it. When it is created, it is given a subset of the permissions below, and it never has more than its creator's role grants, even if the role changes later. A token can have an expiration date, which is recommended for tokens stored on a workstation. Keep tokens out of source control, and provide them through an environment variable or a secret store.

A request that is not authenticated, or that the token's permissions do not allow, is refused with 403 and a body that says why:

{
  "error": "The Authorization header is missing. Send `Authorization: Bearer <api token>`.",
  "code": "AUTHORIZATION_HEADER_MISSING"
}
codeMeaning
AUTHORIZATION_HEADER_MISSINGThe request has no Authorization header.
AUTHORIZATION_HEADER_INVALIDThe header is not of the form Bearer <api token>.
API_TOKEN_NOT_FOUNDNo token matches. It may have been revoked, or its organization disabled.
API_TOKEN_EXPIREDThe token's expiration date has passed. The message says when. Create a new token.
API_TOKEN_OWNER_REMOVEDThe member who created the token no longer belongs to the organization. Create a new token.
INSUFFICIENT_PERMISSIONSThe token is valid but lacks the permission the endpoint needs. The endpoint table below names each one.

Permissions

Each endpoint needs one permission, named in the endpoints table. The permissions the Admin API uses are:

ResourcePermissions
Projectsprojects:read, projects:create, projects:update, projects:delete
Environmentsenvironments:read, environments:create, environments:update, environments:delete
Configsconfigs:read, configs:create, config-settings:update, config-targeting-rules:update, configs:archive
Segmentssegments:read, segments:create, segments:update, segments:delete
Tagstags:read, tags:create, tags:update, tags:delete

Creating a config with tags needs config-settings:update as well as configs:create. Members, API tokens, SDK keys, contexts, and the audit log are managed in the dashboard only.

Terraform, OpenTofu, and the audit log

Every change made through the API is recorded in the audit log with the source API and the token's name. A client that is Terraform or OpenTofu says so with the X-SourceClient header, whose accepted values are terraform and opentofu, so the audit log shows which one made the change. Any other value is recorded as API. The Terraform provider sends the header for you.

Responses and errors

StatusWhen
200The request succeeded and the body holds the resource.
204The request succeeded and there is nothing to return: updating a project or targeting rules, archiving a config, and deletions.
400The body failed validation. The response lists each problem, with the field it concerns when there is one. A config key that is already in use in the project is reported this way too.
403Not authenticated, or the token lacks the permission. See Authentication.
404No resource with that id or key exists in the project or organization.
409Deleting a segment that the targeting rules of a config still use. The body's usages lists each config and the environments whose rules use it.
413The request body is larger than 4 MB.
429Service is suspended, because a Free organization has stayed over its free allowance past the billing grace period or a Pay as you go organization has reached its spending limit. The body is { "error": "Service suspended", "code": "SERVICE_SUSPENDED" } with a Retry-After header. A Free organization that has used up an hourly JSON Schema budget gets 429 too, with a message that says when the budget resets.

A 400 body:

{
  "errors": [
    { "name": "key", "message": "The key must be at least 4 characters long" }
  ]
}

Usage

Each request counts as one Admin API request against your organization's monthly free allowance of 10,000, and beyond it at the Pay as you go rates. Terraform applies and MCP tool calls count the same way, since both go through the API. Reading the OpenAPI document is free.

Endpoints

Projects

MethodPathWhat it doesPermission
GET/projectsList the organization's projects, without their environments.projects:read
POST/projectsCreate a project from a name and a slug. Returns it with its environments, Test and Production.projects:create
GET/projects/{projectId}Get a project with its environments.projects:read
PUT/projects/{projectId}Rename a project or change its slug.projects:update
DELETE/projects/{projectId}Delete a project with everything in it.projects:delete

Environments

MethodPathWhat it doesPermission
GET/projects/{projectId}/environmentsList the project's environments.environments:read
POST/projects/{projectId}/environmentsCreate an environment from a name, a slug, a color, and whether it is live.environments:create
GET/projects/{projectId}/environments/{environmentId}Get an environment.environments:read
PUT/projects/{projectId}/environments/{environmentId}Update an environment's name, slug, color, or live flag.environments:update
DELETE/projects/{projectId}/environments/{environmentId}Delete an environment and everything in it.environments:delete

Configs

MethodPathWhat it doesPermission
GET/projects/{projectId}/configsList the project's configs, without targeting rules. Repeat tagIds to list the configs that have any of those tags, or send untagged=true for the configs without tags.configs:read
POST/projects/{projectId}/configsCreate a config from its key, role, lifetime, type, and defaultValue, which becomes the default targeting rule value in every environment. Optional: description, typeOptions for the type's constraints, client and server availability, variations, and tagIds.configs:create
GET/projects/{projectId}/configs/{configKey}Get a config with its targeting rules in every environment.configs:read
PATCH/projects/{projectId}/configs/{configKey}Update the config's settings: key, description, role, lifetime, type, typeOptions, variations, availability, or tagIds. Only the fields sent change.config-settings:update
PUT/projects/{projectId}/configs/{configKey}/targetsReplace the targeting rules of one environment. See Updating targeting rules.config-targeting-rules:update
GET/projects/{projectId}/configs/{configKey}/activityThe time of the most recent evaluation per environment, SDK key kind, SDK name, and SDK version.configs:read
DELETE/projects/{projectId}/configs/{configKey}Archive the config. It can be restored from the dashboard for 30 days.configs:archive

A config's type is one of boolean, string, integer, float, enum, url, json, or timespan, and its role is config, flag, kill-switch, or experiment. typeOptions carries the constraints of the type: isInteger, min, and max for numbers, values and valueType for an enum, useSchema and schema for JSON, unit, min, max, and allowFractions for a timespan, and secureOnly for a URL. Configs Anatomy explains each.

Segments

MethodPathWhat it doesPermission
GET/projects/{projectId}/segmentsList the project's segments, each with the configs and environments whose rules use it.segments:read
POST/projects/{projectId}/segmentsCreate a segment from a key, a name, its condition groups, and optional environment overrides, a map from environment id to that environment's own groups.segments:create
GET/projects/{projectId}/segments/{segmentKey}Get a segment.segments:read
PUT/projects/{projectId}/segments/{segmentKey}Replace the segment's key, name, and groups. When overrides is sent, the environment overrides become exactly that map, so {} removes them all; when it is left out, they stay.segments:update
DELETE/projects/{projectId}/segments/{segmentKey}Delete the segment and its overrides. Refused with 409 while any config's rules use it.segments:delete

Tags

MethodPathWhat it doesPermission
GET/projects/{projectId}/tagsList the project's tags by name.tags:read
POST/projects/{projectId}/tagsCreate a tag. Names are trimmed, 1 to 50 characters, and unique in the project ignoring case.tags:create
GET/projects/{projectId}/tags/by-nameFind a tag by name, ignoring surrounding whitespace and case.tags:read
GET/projects/{projectId}/tags/{tagId}Get a tag.tags:read
PUT/projects/{projectId}/tags/{tagId}Rename a tag. Its id, and every config assignment, stay the same.tags:update
DELETE/projects/{projectId}/tags/{tagId}Delete a tag. Configs that had it lose the assignment.tags:delete

Examples

List the projects of the organization:

curl https://api.configdirector.com/v1/projects \
  -H "Authorization: Bearer ${CONFIGDIRECTOR_TOKEN}"

Create a temporary feature flag that starts off in every environment:

curl -X POST https://api.configdirector.com/v1/projects/${PROJECT_ID}/configs \
  -H "Authorization: Bearer ${CONFIGDIRECTOR_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "new-checkout",
    "description": "The redesigned checkout flow",
    "role": "flag",
    "lifetime": "temporary",
    "type": "boolean",
    "defaultValue": false
  }'

Updating targeting rules

PUT /projects/{projectId}/configs/{configKey}/targets replaces the rules of one environment. The body names the environment, the default targeting rule value, and the rules in order. Each rule, condition, and percentage carries an id, a UUID you generate.

A conditional rule serves true to two named users, and the default targeting rule serves false to everyone else:

curl -X PUT https://api.configdirector.com/v1/projects/${PROJECT_ID}/configs/new-checkout/targets \
  -H "Authorization: Bearer ${CONFIGDIRECTOR_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "environmentId": "'"${ENVIRONMENT_ID}"'",
    "defaultValue": false,
    "rules": [
      {
        "id": "7a6b0d1e-3b4e-4a8e-9c3b-1f2e3d4c5b6a",
        "type": "conditional",
        "order": 0,
        "target": "value",
        "value": true,
        "conditions": [
          {
            "id": "0c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
            "kind": "attribute",
            "attribute": "identifier",
            "operator": "is one of",
            "targetType": "text",
            "targetValues": ["user-101", "user-202"]
          }
        ]
      }
    ]
  }'

A rule has a type of conditional or percentage. A conditional rule holds conditions, every one of which must match, and either a target of value with the value to serve or a target of percentage with percentages, a list of { id, percentage, value } that adds up to 100. A percentage rule holds only percentages. An attribute condition tests identifier, kind, name, appName, appVersion, or traits with a trait JSON pointer, read as the targetType text, number, semver, datetime, array, or boolean, each with its own operators. A segment condition is { id, kind: "segment", operator: "in" | "not in", segmentId }. The OpenAPI document lists every operator per target type, and the Terraform provider page shows the same rules in HCL.

Rules are validated against the config's type and constraints before they are saved, exactly as in the dashboard: a value outside an integer's range, a URL that is not HTTPS on a secure-only config, or a JSON value that fails the config's schema is refused with 400.