Skip to main content
GrowthBook offers a full REST API for interacting with the application. Request data can use either JSON or Form data encoding (with proper Content-Type headers). All response bodies are JSON-encoded. The API base URL for GrowthBook Cloud is https://api.growthbook.io/api. For self-hosted deployments, it is the same as your API_HOST environment variable (defaults to http://localhost:3100/api). The rest of these docs will assume you are using GrowthBook Cloud.

Versioning

Endpoints are versioned by path prefix:
  • /v1/... — stable, widely-supported endpoints
  • /v2/... — updated endpoints with improved shapes (e.g. unified per-rule environment scope for feature flags)
New integrations should prefer v2 where available. Feature-flag and metric v1 routes are deprecated: they are tagged LEGACY in the sidebar and collapsed by default. Use the matching v2 group when both exist.

Authentication

We support both the HTTP Basic and Bearer authentication schemes for convenience. You first need to generate a new API Key in GrowthBook. Different keys have different permissions:
  • Personal Access Tokens: These are sensitive and provide the same level of access as the user has to an organization, or less if the token’s permissions are limited. These can be created by going to Personal Access Tokens under your user menu. Members with the API Keys Manage members’ tokens permission can disable a member’s token under Settings -> Manage PATs, and admins can require new tokens to expire within a maximum lifetime.
  • Secret Keys: These are sensitive and provide the level of access of the role they are given, which can be any built-in or custom role, with optional per-project role overrides and environment limits. Managing Secret Keys on behalf of an organization takes the API Keys permissions. These can be created by going to Settings -> API Keys, where Admins can also require new Secret Keys to expire within a maximum lifetime.
If using HTTP Basic auth, pass the Secret Key as the username and leave the password blank (when using curl, add : at the end of the secret to indicate an empty password)
If using Bearer auth, pass the Secret Key as the token:
If a key has an expiration date, every response includes it in the X-GrowthBook-Key-Expires-At header (ISO 8601), so scripts can warn before the key stops working. Requests made with an expired key fail with a 401 that says where to create a replacement. See Expiration for choosing a key’s expiration, the warnings before it lapses, and the organization policies.

Naming who asked

Requests made with a Secret Key may add an X-GrowthBook-Requested-By header naming the organization member who asked for the change, as a user id or an email address. History, revision logs and webhooks show that member next to the key. Each key’s settings under Settings -> API Keys:
  • Header: Optional (the default) uses the header when it’s sent, Required rejects requests without it, and Rejected rejects requests that send it, each with a 400.
  • Permissions, when a member is named:
    • Assume member’s role (the default): the request acts as that member, with only what both the key and the member can do, so the header can narrow a key but never widen it. Drafts, owners, mine filters and reviews are the member’s. The member’s rights over their own drafts, comments and verdicts apply only where the key’s own role allows the same action.
    • Use key’s role: the key acts as itself, with its own permissions, and the name is only recorded in history. Drafts, verdicts and ownership are the key’s, as when no member is named.
A key that names no one, or uses its own role, acts as itself: it can draft and review with its own permissions, and its verdicts are judged on its role. A key belongs to no team, so its approval never satisfies a rule that requires approval from a team. No one can rule on a draft they created, and a key acting as itself can’t rule on a draft it created or edited in either mode. An approval a key gives while assuming a member counts only where both the key and the member could approve, and stops counting if the key is disabled, expires or is deleted. Because the header isn’t verified, whoever holds the key can act as any member. A value that does not match a member of the organization is rejected with a 400. A create request that omits owner defaults it to the member whose role the key assumes. Scheduled and auto-publishes run later with the permissions of the request that armed them, and don’t run if that member has left the organization, the key has expired, or the key no longer assumes members’ roles. Personal Access Tokens and OAuth tokens already act as their user and reject the header.

Naming and human review

People review what the API creates in the GrowthBook UI.
  • Keep keys and names short (2-5 words). Follow your organization’s Feature Flag key format (featureRegexValidator and featureKeyExample in GET /v1/settings), or use kebab-case if it has none. Feature Flag keys can’t be changed after creation, and an experiment’s tracking key shouldn’t change after launch.
  • Put context (why, plan, tickets, links) in description, not in names or keys.
  • Group with tags, not name prefixes. Projects (project or projects) control access and where a resource can be used, so set them deliberately instead of using them as labels.
  • To create a Feature Flag disabled with POST /v2/features, list every environment in environments with enabled: false (on POST /v1/features, each entry also needs rules: []). An environment you leave out uses its default state, which may be enabled.
  • Leave publishing and production changes to a person unless asked.
  • If a request is blocked (an approval requirement, a warning, a Custom Hook, schema validation or a permission error), stop and ask a person. Don’t retry with an override field, a different key or another workaround unless a person asked you to. If a write answers 202 with a confirmation, give a person its url and wait (see Waiting for confirmation).

Waiting for confirmation

A key can require a person to confirm some writes before they run (see API Keys for Agents). A held write doesn’t run. It answers 202 Accepted with the confirmation, a Location header to poll, and a Retry-After header with the seconds to wait between polls:
Give the person the url, then poll GET /v1/confirmations/{id}. Pass wait (in seconds, up to 30) to hold the poll open until the status changes:
note carries anything the person left for the agent when they decided. actions lists what the request was held for, each with the environments it touches.
  • Only the key that made the request, or another token of the same person, can read the confirmation.
  • Sending the same request again while it’s pending returns the same confirmation.
  • A request that publishes, reverts or archives, or that changes a Feature Flag or an Experiment’s status, schedule, targeting or traffic, isn’t run if what it acts on changed after it was held. Other writes, such as editing settings or a draft, run as sent, so they can overwrite changes made while they waited.
  • A confirmed request runs once, with the key’s permissions (or the member’s role it assumes), not the confirmer’s. Send it again to retry, which asks for a new confirmation.
  • Confirming isn’t a review approval.

Errors

The API may return the following error status codes:
  • 400 - Bad Request - Often due to a missing required parameter
  • 401 - Unauthorized - No valid API key provided
  • 402 - Request Failed - The parameters are valid, but the request failed
  • 403 - Forbidden - Provided API key does not have the required access
  • 404 - Not Found - Unknown API route or requested resource
  • 422 - Unprocessable Entity - The request is valid, but a warning, validation rule, approval requirement, or another publishing gate blocked it. Do not assume that ignoreWarnings clears every 422 response.
  • 429 - Too Many Requests - You exceeded the rate limit of 60 requests per minute, or the limit your self-hosted server sets. Try again later.
  • 5XX - Server Error - Something went wrong on GrowthBook’s end (these are rare)
The response body will be a JSON object with the following properties:
  • message - Information about the error

Publishing gates

Automated callers, including AI agents, should report a blocked response to a person instead of retrying with an override. Use an override only when a person has explicitly asked for it. Publish responses include a gates array that explains every blocker:
  • type, severity, and messages identify the problem.
  • override names the request-body field that can bypass it. This is ignoreWarnings for warnings, skipSchemaValidation for schema and invariant failures, or skipHooks for Custom Hook rejections. A value of null means there is no request-body override.
  • requiresPermission identifies any additional permission needed to use the override.
  • resolution provides an API action, method, and path when the blocker must be resolved another way.
For example, an approval gate is cleared by approving the revision or by using a caller with Bypass draft approvals access. A Config lock is cleared through the unlock route in resolution. When a successful publish bypasses a gate, the response includes bypassedGates. Each entry reports the gate type and how it was bypassed in via, which is one of ignoreWarnings, skipSchemaValidation, skipHooks, bypassApprovalPermission, restApiBypassesReviews, or revertsBypassApproval (reverts only). This field is omitted when no gates were bypassed.