Set (or update) a config's per-source render projection on a draft
Stages a per-source render projection on the draft, AND the schema it implies. Provide a named schema source ({ type: "typescript" | "protobuf" | "python" | "go" | "rust" | "json-schema", value }) for the consuming codebase identified by source: GrowthBook derives the config’s canonical schema from it (so the change projects into the Config) and captures that source’s named-type structure under renderProjections[source]. Both are staged on the draft and published through the normal flow. Pass version: "new" to auto-create a draft. Lossy conversions degrade with warnings.
curl -X PUT 'https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection' \
-H 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection"
payload = {
"source": "<string>",
"schema": {
"type": "json-schema",
"value": {}
},
"revisionTitle": "<string>",
"revisionComment": "<string>",
"additionalProperties": True,
"ignoreWarnings": True,
"skipSchemaValidation": True,
"skipHooks": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source: '<string>',
schema: {type: 'json-schema', value: {}},
revisionTitle: '<string>',
revisionComment: '<string>',
additionalProperties: true,
ignoreWarnings: true,
skipSchemaValidation: true,
skipHooks: true
})
};
fetch('https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'source' => '<string>',
'schema' => [
'type' => 'json-schema',
'value' => [
]
],
'revisionTitle' => '<string>',
'revisionComment' => '<string>',
'additionalProperties' => true,
'ignoreWarnings' => true,
'skipSchemaValidation' => true,
'skipHooks' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection"
payload := strings.NewReader("{\n \"source\": \"<string>\",\n \"schema\": {\n \"type\": \"json-schema\",\n \"value\": {}\n },\n \"revisionTitle\": \"<string>\",\n \"revisionComment\": \"<string>\",\n \"additionalProperties\": true,\n \"ignoreWarnings\": true,\n \"skipSchemaValidation\": true,\n \"skipHooks\": true\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source\": \"<string>\",\n \"schema\": {\n \"type\": \"json-schema\",\n \"value\": {}\n },\n \"revisionTitle\": \"<string>\",\n \"revisionComment\": \"<string>\",\n \"additionalProperties\": true,\n \"ignoreWarnings\": true,\n \"skipSchemaValidation\": true,\n \"skipHooks\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": \"<string>\",\n \"schema\": {\n \"type\": \"json-schema\",\n \"value\": {}\n },\n \"revisionTitle\": \"<string>\",\n \"revisionComment\": \"<string>\",\n \"additionalProperties\": true,\n \"ignoreWarnings\": true,\n \"skipSchemaValidation\": true,\n \"skipHooks\": true\n}"
response = http.request(request)
puts response.read_body{
"revision": {
"id": "<string>",
"status": "draft",
"authorId": "<string>",
"reviews": [
{
"id": "<string>",
"userId": "<string>",
"decision": "approve",
"dateCreated": "2023-11-07T05:31:56Z",
"comment": "<string>",
"stale": true,
"user": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
}
}
],
"activityLog": [
{
"id": "<string>",
"userId": "<string>",
"action": "created",
"dateCreated": "2023-11-07T05:31:56Z",
"description": "<string>",
"proposedChangesSnapshot": [
{
"op": "add",
"path": "<string>",
"value": "<unknown>"
}
],
"targetSnapshot": "<unknown>",
"user": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
}
}
],
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"baseConfig": {
"id": "<string>",
"key": "<string>",
"name": "<string>",
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"owner": "<string>",
"ownerEmail": "<string>",
"parent": "<string>",
"extends": [
"<string>"
],
"value": {},
"scopedOverrides": [
{
"config": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
}
],
"scopedConfig": {
"parent": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
},
"description": "<string>",
"project": "<string>",
"archived": true,
"schema": {
"type": "json-schema",
"value": {}
},
"extensible": true,
"invariants": [
{
"name": "<string>",
"rule": {},
"message": "<string>"
}
],
"locked": true,
"experimentGuard": true,
"lockedRevision": {
"id": "<string>",
"version": 123
},
"lockedBy": "<string>",
"dateLocked": "2023-11-07T05:31:56Z"
},
"proposedConfig": {
"id": "<string>",
"key": "<string>",
"name": "<string>",
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"owner": "<string>",
"ownerEmail": "<string>",
"parent": "<string>",
"extends": [
"<string>"
],
"value": {},
"scopedOverrides": [
{
"config": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
}
],
"scopedConfig": {
"parent": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
},
"description": "<string>",
"project": "<string>",
"archived": true,
"schema": {
"type": "json-schema",
"value": {}
},
"extensible": true,
"invariants": [
{
"name": "<string>",
"rule": {},
"message": "<string>"
}
],
"locked": true,
"experimentGuard": true,
"lockedRevision": {
"id": "<string>",
"version": 123
},
"lockedBy": "<string>",
"dateLocked": "2023-11-07T05:31:56Z"
},
"proposedChanges": [
{
"op": "add",
"path": "<string>",
"value": "<unknown>"
}
],
"version": 123,
"title": "<string>",
"author": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
},
"authorEmail": "<string>",
"contributors": [
"<string>"
],
"revertedFrom": "<string>",
"autoPublishOnApproval": true,
"autoPublishEnabledBy": "<string>",
"autoPublishEnabledByUser": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
},
"scheduledPublishAt": "2023-11-07T05:31:56Z",
"scheduledPublishLockEdits": true,
"scheduledPublishLockOthers": true,
"scheduledPublishBypassApproval": true,
"scheduledPublishAttempts": 123,
"scheduledPublishLastError": "<string>",
"scheduledPublishGaveUpAt": "2023-11-07T05:31:56Z",
"resolution": {
"action": "merged",
"userId": "<string>",
"dateCreated": "2023-11-07T05:31:56Z",
"user": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
}
}
},
"warnings": [
{
"code": "dropped-declaration",
"message": "<string>",
"path": "<string>"
}
]
}{
"confirmation": {
"id": "<string>",
"status": "pending",
"actions": [
{
"action": "feature.create",
"environments": [
"<string>"
]
}
],
"summary": "<string>",
"url": "<string>",
"expiresAt": "<string>",
"response": {
"status": 123,
"body": "<unknown>"
},
"note": "<string>"
},
"message": "<string>"
}Authorizations
If using Bearer auth, pass the Secret Key as the token:
curl https://api.growthbook.io/api/v1/features -H "Authorization: Bearer secret_abc123DEF456"
Query Parameters
Deprecated — pass skipSchemaValidation in the request body instead.
"true"Deprecated — pass ignoreWarnings in the request body instead.
"true"Body
Identifier of the consuming codebase/service this projection belongs to.
The named schema source for this projection. Its type names are captured; its structure derives the config's canonical schema.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
Show child attributes
Show child attributes
Short draft title (e.g. Enable for beta testers). Only used when version is "new"; ignored for existing drafts.
Markdown. What changed and why, for reviewers. Only used when version is "new"; ignored for existing drafts.
Whether the resulting object schema permits extra keys (family extensibility).
Set to true to acknowledge the warnings listed in a blocked response and continue. This covers experiment guards, locked dependents, and references affected by an archive. When the organization treats schema failures as warnings, it also covers schema and invariant warnings. It never bypasses a rejected Custom Hook. On revision publish endpoints, it can also force-publish an out-of-date draft when the caller has Bypass draft approvals access. Only set this when a person has explicitly asked you to. If a check blocks you, stop and ask a person instead of working around it.
Set to true to publish despite schema validation errors, failed invariants, or schema changes that invalidate dependent resources. This does not bypass a rejected Custom Hook; use skipHooks for that. The caller must have Bypass draft approvals access for Feature Flags, Configs, and Constants in every Project. Otherwise, this field is ignored. Only set this when a person has explicitly asked you to. If a check blocks you, stop and ask a person instead of working around it.
Set to true to publish despite a Custom Hook rejection. This does not bypass schema validation; use skipSchemaValidation for that. The caller must have Bypass draft approvals access for Feature Flags, Configs, and Constants in every Project. Otherwise, this field is ignored. Only set this when a person has explicitly asked you to. If a check blocks you, stop and ask a person instead of working around it.
Was this page helpful?
curl -X PUT 'https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection' \
-H 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection"
payload = {
"source": "<string>",
"schema": {
"type": "json-schema",
"value": {}
},
"revisionTitle": "<string>",
"revisionComment": "<string>",
"additionalProperties": True,
"ignoreWarnings": True,
"skipSchemaValidation": True,
"skipHooks": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source: '<string>',
schema: {type: 'json-schema', value: {}},
revisionTitle: '<string>',
revisionComment: '<string>',
additionalProperties: true,
ignoreWarnings: true,
skipSchemaValidation: true,
skipHooks: true
})
};
fetch('https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'source' => '<string>',
'schema' => [
'type' => 'json-schema',
'value' => [
]
],
'revisionTitle' => '<string>',
'revisionComment' => '<string>',
'additionalProperties' => true,
'ignoreWarnings' => true,
'skipSchemaValidation' => true,
'skipHooks' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection"
payload := strings.NewReader("{\n \"source\": \"<string>\",\n \"schema\": {\n \"type\": \"json-schema\",\n \"value\": {}\n },\n \"revisionTitle\": \"<string>\",\n \"revisionComment\": \"<string>\",\n \"additionalProperties\": true,\n \"ignoreWarnings\": true,\n \"skipSchemaValidation\": true,\n \"skipHooks\": true\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source\": \"<string>\",\n \"schema\": {\n \"type\": \"json-schema\",\n \"value\": {}\n },\n \"revisionTitle\": \"<string>\",\n \"revisionComment\": \"<string>\",\n \"additionalProperties\": true,\n \"ignoreWarnings\": true,\n \"skipSchemaValidation\": true,\n \"skipHooks\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.growthbook.io/api/v1/configs-revisions/{key}/{version}/projection")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": \"<string>\",\n \"schema\": {\n \"type\": \"json-schema\",\n \"value\": {}\n },\n \"revisionTitle\": \"<string>\",\n \"revisionComment\": \"<string>\",\n \"additionalProperties\": true,\n \"ignoreWarnings\": true,\n \"skipSchemaValidation\": true,\n \"skipHooks\": true\n}"
response = http.request(request)
puts response.read_body{
"revision": {
"id": "<string>",
"status": "draft",
"authorId": "<string>",
"reviews": [
{
"id": "<string>",
"userId": "<string>",
"decision": "approve",
"dateCreated": "2023-11-07T05:31:56Z",
"comment": "<string>",
"stale": true,
"user": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
}
}
],
"activityLog": [
{
"id": "<string>",
"userId": "<string>",
"action": "created",
"dateCreated": "2023-11-07T05:31:56Z",
"description": "<string>",
"proposedChangesSnapshot": [
{
"op": "add",
"path": "<string>",
"value": "<unknown>"
}
],
"targetSnapshot": "<unknown>",
"user": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
}
}
],
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"baseConfig": {
"id": "<string>",
"key": "<string>",
"name": "<string>",
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"owner": "<string>",
"ownerEmail": "<string>",
"parent": "<string>",
"extends": [
"<string>"
],
"value": {},
"scopedOverrides": [
{
"config": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
}
],
"scopedConfig": {
"parent": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
},
"description": "<string>",
"project": "<string>",
"archived": true,
"schema": {
"type": "json-schema",
"value": {}
},
"extensible": true,
"invariants": [
{
"name": "<string>",
"rule": {},
"message": "<string>"
}
],
"locked": true,
"experimentGuard": true,
"lockedRevision": {
"id": "<string>",
"version": 123
},
"lockedBy": "<string>",
"dateLocked": "2023-11-07T05:31:56Z"
},
"proposedConfig": {
"id": "<string>",
"key": "<string>",
"name": "<string>",
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"owner": "<string>",
"ownerEmail": "<string>",
"parent": "<string>",
"extends": [
"<string>"
],
"value": {},
"scopedOverrides": [
{
"config": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
}
],
"scopedConfig": {
"parent": "<string>",
"environments": [
"<string>"
],
"projects": [
"<string>"
]
},
"description": "<string>",
"project": "<string>",
"archived": true,
"schema": {
"type": "json-schema",
"value": {}
},
"extensible": true,
"invariants": [
{
"name": "<string>",
"rule": {},
"message": "<string>"
}
],
"locked": true,
"experimentGuard": true,
"lockedRevision": {
"id": "<string>",
"version": 123
},
"lockedBy": "<string>",
"dateLocked": "2023-11-07T05:31:56Z"
},
"proposedChanges": [
{
"op": "add",
"path": "<string>",
"value": "<unknown>"
}
],
"version": 123,
"title": "<string>",
"author": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
},
"authorEmail": "<string>",
"contributors": [
"<string>"
],
"revertedFrom": "<string>",
"autoPublishOnApproval": true,
"autoPublishEnabledBy": "<string>",
"autoPublishEnabledByUser": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
},
"scheduledPublishAt": "2023-11-07T05:31:56Z",
"scheduledPublishLockEdits": true,
"scheduledPublishLockOthers": true,
"scheduledPublishBypassApproval": true,
"scheduledPublishAttempts": 123,
"scheduledPublishLastError": "<string>",
"scheduledPublishGaveUpAt": "2023-11-07T05:31:56Z",
"resolution": {
"action": "merged",
"userId": "<string>",
"dateCreated": "2023-11-07T05:31:56Z",
"user": {
"type": "dashboard",
"id": "<string>",
"apiKey": "<string>",
"name": "<string>",
"email": "<string>",
"requestedBy": {
"id": "<string>",
"name": "<string>",
"email": "<string>"
},
"assumedRole": true
}
}
},
"warnings": [
{
"code": "dropped-declaration",
"message": "<string>",
"path": "<string>"
}
]
}{
"confirmation": {
"id": "<string>",
"status": "pending",
"actions": [
{
"action": "feature.create",
"environments": [
"<string>"
]
}
],
"summary": "<string>",
"url": "<string>",
"expiresAt": "<string>",
"response": {
"status": 123,
"body": "<unknown>"
},
"note": "<string>"
},
"message": "<string>"
}
