{"id":"flags.set","module":"observability","namespace":"flags","action":"set","method":"POST","path":"/v1/flags/set","idempotent":true,"available":true,"vendors":[],"vendors_ready":[],"vendors_pending":[],"key_status":"live","default_vendor":null,"self_hosted":true,"minimum_tier":"standard","supported_message_classes":null,"regions":["western","china"],"dynamic_params":{},"models_tracked":false,"sdk_hint":"Regular parameters + types are stable — read them from the typed SDK signature / API reference for this capability. discovery only carries the runtime-dynamic values above (available, vendors, dynamic_params).","params":{"title":"FlagSetRequest","description":"Request shape for flags.set (POST /v1/flags, upsert). SDK ergonomic surface = flag.create(key, description, ...) and flag.update(key, **patch, version) both map here. Create omits version (server assigns version=1). Update MUST carry the current version (integer>=1) for optimistic locking (FLAG_VERSION_CONFLICT). Returns the full Flag.","type":"object","required":["key"],"additionalProperties":false,"properties":{"key":{"type":"string","pattern":"^[a-z0-9_.-]{1,128}$","description":"Unique identifier key for this resource"},"description":{"type":["string","null"],"minLength":5,"maxLength":500,"description":"Required on create (FLAG_DESCRIPTION_TOO_SHORT if <5 chars)."},"type":{"type":["string","null"],"enum":["bool","string","number","json",null],"description":"Flag value type (enums/flag_type.yaml). Defaults to bool on create."},"default_value":{"description":"Value returned when no rule matches; type must match `type` (FLAG_TYPE_MISMATCH)."},"rules":{"type":["array","null"],"items":{"title":"FlagRule","description":"Conditional rule on a feature flag. if_ is a recursive predicate using enums/flag_operator.yaml; then is the value returned when matched.","type":"object","required":["if","then"],"additionalProperties":false,"properties":{"if":{"description":"Predicate object. Top-level keys are context field paths (e.g. 'user_id', 'context.country') OR boolean composition keys ($and / $or / $not). Leaf values are operator objects { eq: ..., in: [...], gte: ..., matches: '...', percentage: N, cohort: 'cohort_id', ... }.","type":"object"},"then":{"description":"Value returned when the predicate matches. Type must match flag.type."},"description":{"type":["string","null"],"description":"Human-readable explanation."}}},"description":"Targeting rules for the flag"},"rollout":{"oneOf":[{"title":"RolloutConfig","description":"Percentage / sticky-bucket rollout config attached to a feature flag. See docs/Infrai_SDK_Observability.md §1.2.","type":"object","required":["percentage","salt","sticky_unit"],"additionalProperties":false,"properties":{"percentage":{"type":"integer","minimum":0,"maximum":100,"description":"Rollout percentage (0-100)"},"salt":{"type":"string","description":"Consistent-hash salt; rotate to reshuffle bucket assignments."},"variants":{"type":["array","null"],"items":{"title":"Variant","description":"One variant inside a multi-variant rollout (A/B/C test). See docs/Infrai_SDK_Observability.md §1.2.","type":"object","required":["value","weight"],"additionalProperties":false,"properties":{"value":{"description":"Variant value; type must match flag.type."},"weight":{"type":"integer","minimum":0,"maximum":100,"description":"0..100; sum of weights must be <= rollout.percentage."}}},"description":"Variant definitions for the flag"},"sticky_unit":{"enum":["user_id","session_id","device_id"],"default":"user_id","description":"Sticky unit for consistent rollout assignment"}}},{"type":"null"}],"description":"Rollout configuration for gradual delivery"},"tags":{"type":["object","null"],"description":"Tags for categorization and filtering"},"enabled":{"type":["boolean","null"],"default":true,"description":"Whether this feature or configuration is enabled"},"version":{"type":["integer","null"],"minimum":1,"description":"Required for update (optimistic lock). Omit for create."}}},"response":{"title":"Flag","type":"object","required":["key","type","default_value","enabled","version","created_at","updated_at"],"additionalProperties":false,"properties":{"key":{"type":"string","pattern":"^[a-z0-9_.-]{1,128}$","description":"Unique identifier key for this resource"},"description":{"type":"string","minLength":5,"maxLength":500,"description":"Free-text description of this resource"},"type":{"enum":["bool","string","number","json"],"description":"Type discriminator for this resource"},"default_value":{"description":"Default value when no rules match"},"enabled":{"type":"boolean","default":true,"description":"Whether this feature or configuration is enabled"},"rules":{"type":"array","items":{"type":"object"},"description":"Targeting rules for the flag"},"rollout":{"type":["object","null"],"description":"Rollout configuration for gradual delivery"},"tags":{"type":["object","null"],"description":"Tags for categorization and filtering"},"version":{"type":"integer","minimum":1,"description":"Optimistic-lock counter."},"created_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp when this resource was created"},"created_by":{"type":"string","description":"User who created this flag"},"updated_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp when this resource was last updated"},"updated_by":{"type":"string","description":"User who last updated this flag"},"archived_at":{"type":["string","null"],"format":"date-time","description":"ISO 8601 timestamp when this flag was archived"}}},"errors":["ACCOUNT_AUTORECHARGE_LIMIT","ACCOUNT_FROZEN","AUTH_RATE_LIMIT","AUTH_REFRESH_TOO_FREQUENT","COLD_TIER_NOT_ENABLED","ERROR_EVENT_NOT_FOUND","ERROR_GROUP_NOT_FOUND","ERROR_TAGS_HIGH_CARDINALITY","FLAG_ALREADY_EXISTS","FLAG_DESCRIPTION_TOO_SHORT","FLAG_KEY_INVALID","FLAG_NOT_FOUND","FLAG_RULE_INVALID","FLAG_TYPE_MISMATCH","FLAG_VERSION_CONFLICT","IDEMPOTENCY_KEY_CONFLICT","INSUFFICIENT_CREDIT","INTERNAL_ERROR","INVALID_ARGUMENT","KEY_REVOKED","MAINTENANCE","NETWORK_ERROR","RATE_LIMIT_ACCOUNT","RATE_LIMIT_USER","RATE_LIMIT_VENDOR","RETENTION_FOREVER_NOT_ALLOWED","RETENTION_HARD_CAP_EXCEEDED","SCOPE_INSUFFICIENT","UNAUTHORIZED","VENDOR_AUTH_ERROR","VENDOR_DOWN","VENDOR_TIMEOUT","WALLET_EXPIRED"],"examples":{"curl":"curl -X POST https://api.infrai.cc/v1/flags/set \\\n  -H \"Authorization: Bearer $INFRAI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"key\": \"sample\"}'","python":"# Zero-install REST call — no SDK required (short-term the API is REST-only).\nimport os, requests\n\nresp = requests.post(\n    \"https://api.infrai.cc/v1/flags/set\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['INFRAI_API_KEY']}\",\n    },\n    json={'key': 'sample'},\n)\nresp.raise_for_status()\nprint(resp.json())","javascript":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nconst resp = await fetch(\n  \"https://api.infrai.cc/v1/flags/set\",\n  {\n    method: \"POST\",\n    headers: {\n      \"Authorization\": `Bearer ${process.env.INFRAI_API_KEY}`,\n      \"Content-Type\": \"application/json\",\n    },\n    body: JSON.stringify({\"key\": \"sample\"}),\n  },\n);\nconsole.log(await resp.json());","typescript":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nconst resp = await fetch(\n  \"https://api.infrai.cc/v1/flags/set\",\n  {\n    method: \"POST\",\n    headers: {\n      \"Authorization\": `Bearer ${process.env.INFRAI_API_KEY}`,\n      \"Content-Type\": \"application/json\",\n    },\n    body: JSON.stringify({\"key\": \"sample\"}),\n  },\n);\nif (!resp.ok) throw new Error(`infrai ${resp.status}`);\nconst data: unknown = await resp.json();\nconsole.log(data);","go":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\tbody := []byte(`{\"key\": \"sample\"}`)\n\treq, _ := http.NewRequest(\"POST\", \"https://api.infrai.cc/v1/flags/set\", bytes.NewReader(body))\n\treq.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"INFRAI_API_KEY\"))\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n\tfmt.Println(resp.Status)\n}","java":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nimport java.net.URI;\nimport java.net.http.*;\n\nHttpRequest req = HttpRequest.newBuilder()\n    .uri(URI.create(\"https://api.infrai.cc/v1/flags/set\"))\n    .header(\"Authorization\", \"Bearer \" + System.getenv(\"INFRAI_API_KEY\"))\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"POST\", HttpRequest.BodyPublishers.ofString(\"{\\\"key\\\": \\\"sample\\\"}\"))\n    .build();\nHttpResponse<String> resp = HttpClient.newHttpClient()\n    .send(req, HttpResponse.BodyHandlers.ofString());\nSystem.out.println(resp.body());","csharp":"// Zero-install REST call — no SDK required (short-term the API is REST-only).\nusing System;\nusing System.Net.Http;\n\nvar client = new HttpClient();\nvar req = new HttpRequestMessage(new HttpMethod(\"POST\"), \"https://api.infrai.cc/v1/flags/set\");\nvar key = Environment.GetEnvironmentVariable(\"INFRAI_API_KEY\");\nreq.Headers.Add(\"Authorization\", \"Bearer \" + key);\nreq.Content = new StringContent(\"{\\\"key\\\": \\\"sample\\\"}\", System.Text.Encoding.UTF8, \"application/json\");\nvar resp = await client.SendAsync(req);\nConsole.WriteLine(await resp.Content.ReadAsStringAsync());","php":"<?php\n// Zero-install REST call — no SDK required (short-term the API is REST-only).\n$ch = curl_init(\"https://api.infrai.cc/v1/flags/set\");\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, \"POST\");\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\ncurl_setopt($ch, CURLOPT_HTTPHEADER, [\n    \"Authorization: Bearer \" . getenv(\"INFRAI_API_KEY\"),\n    \"Content-Type: application/json\",\n]);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, \"{\\\"key\\\": \\\"sample\\\"}\");\n$response = curl_exec($ch);\ncurl_close($ch);\necho $response;","ruby":"# Zero-install REST call — no SDK required (short-term the API is REST-only).\nrequire \"net/http\"\nrequire \"uri\"\n\nuri = URI(\"https://api.infrai.cc/v1/flags/set\")\nhttp = Net::HTTP.new(uri.host, uri.port)\nhttp.use_ssl = true\nreq = Net::HTTP::Post.new(uri)\nreq[\"Authorization\"] = \"Bearer #{ENV['INFRAI_API_KEY']}\"\nreq[\"Content-Type\"] = \"application/json\"\nreq.body = '{\"key\": \"sample\"}'\nres = http.request(req)\nputs res.body","rust":"// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let resp = reqwest::Client::new()\n        .post(\"https://api.infrai.cc/v1/flags/set\")\n        .header(\"Authorization\", format!(\"Bearer {}\", env::var(\"INFRAI_API_KEY\")?))\n        .header(\"Content-Type\", \"application/json\")\n        .body(r#\"{\"key\": \"sample\"}\"#)\n        .send()\n        .await?;\n    println!(\"{}\", resp.text().await?);\n    Ok(())\n}","request":{"key":"sample"}},"billing":{"is_billable":false,"free":true,"billing_class":"self_dev_market","unit":"per_call","note":"free (rate-limited); does NOT consume the new-account trial"}}