Create Guardrail
POST /environments/{env_id}/guardrails
POST /environments/{env_id}/guardrailsInteractive request editor loads with JavaScript.
Authorization
BearerAdminToken Organization-scoped admin token. Read operations require a valid token, and write operations require a token with write permission.
In: header
Path Parameters
Environment ID that scopes the request.
uuidRequest Body
application/json
Create-guardrail body. config is validated per-kind by the
server; unknown top-level fields are tolerated (see the Guardrails
note above).
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "$AISIX_CP/environments/$ENV_ID/guardrails" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Block exposed access keys", "kind": "keyword", "hook_point": "input", "enforcement_mode": "block", "enabled": true, "config": { "patterns": [ { "kind": "literal", "value": "AKIA" } ] } }'Created
{
"guardrail": {
"id": "eb6a639d-2b4e-4f80-a24d-65a96ac30603",
"env_id": "6fbea7f2-88a7-4cbb-8dca-a0ad785d07c5",
"name": "Block exposed access keys",
"enabled": true,
"hook_point": "input",
"kind": "keyword",
"fail_open": false,
"config": {
"patterns": [
{
"kind": "literal",
"value": "AKIA"
}
]
},
"family": "regex_rule",
"provider": "builtin",
"check_type": "content_moderation",
"enforcement_mode": "block",
"direction": "both",
"created_at": "2026-07-31T09:20:00Z",
"updated_at": "2026-07-31T09:20:00Z"
}
}Request body or parameters failed validation.
{
"error": {
"code": "string",
"message": "string"
}
}Missing or invalid bearer.
{
"error": {
"code": "UNAUTHENTICATED",
"message": "no org context"
}
}Authenticated request is not permitted.
{
"error": {
"code": "CUSTOM_KEY_DISABLED",
"message": "custom API key values are disabled for this organization"
}
}Resource not found.
{
"error": {
"code": "NOT_FOUND",
"message": "provider key not found"
}
}Request conflicts with current resource state.
{
"error": {
"code": "CREDENTIAL_IN_USE",
"message": "models still reference this provider_key"
}
}Complete operation details and schema variants
POST /environments/{env_id}/guardrails
Create Guardrail
Create a guardrail in an environment. The per-kind config
shape is validated by the server against the guardrail catalog
(GET /guardrails/schema); this spec models the stable envelope
and treats config as an open object.
Parameters
env_id(path, string, required): Environment ID that scopes the request.
Request body
Content type: application/json
-
name(string, required): Human-readable guardrail name, unique within the environment. -
enabled(boolean, optional): Whether connected gateways evaluate the guardrail. Omit to create it enabled. -
hook_point(string, optional): Where in the request lifecycle the guardrail executes. This is the runtime control;directionis only metadata. -
kind(string, required): Guardrail provider kind. Fixed at creation. -
fail_open(boolean, optional): Whether a provider failure allows the request to continue. Omit to use the server default of false: a guardrail that could not run does not release the request. Sendtrueto prefer availability over enforcement. Note this governs the INPUT hook only; the output hook has its ownoutput_fail_open, which also defaults to false. -
config(object, optional): Kind-specific configuration validated against the guardrail catalog. Secret values are encrypted before storage.
The read-only projections a GET returns inside config
(api_key_set, access_key_secret_set,
aws_credentials.secret_set, secret_names) may be sent
back here. They are accepted when they match what the
request stores and rejected when they do not; they never
write anything themselves.
kind: pii — custom_patterns[].replacement. Two rules
decide what a masked span becomes, and both are easy to guess
wrong:
- The text is used literally.
$1and other group references are not expanded — unlikeproxy.url_rewriteselsewhere in this product, which does expand them. - If the
regexdeclares at least one capture group, only group 1 of each match is replaced; the rest of the match is kept verbatim. A regex with no capture group replaces the whole match.
Together they make a plausible-looking rule produce a
plausible-looking wrong answer:
regex: "ACCT-([0-9]{4})-([0-9]{4})" with
replacement: "ACCT-$1-****" rewrites ACCT-1234-5678 to
ACCT-ACCT-$1-****-5678 — accepted, and still shaped like
something redacted. To keep surrounding text, leave it outside
the capture group rather than repeating it in the replacement.
Omit replacement for the default [<NAME>_REDACTED] token;
an empty string deletes the span.
-
family(string, optional): Guardrail family metadata. Omitfamily,provider, andcheck_typetogether to derive the canonical triple fromkind. -
provider(string, optional): Provider portion of the guardrail metadata triple. -
check_type(string, optional): Check-type portion of the guardrail metadata triple. -
enforcement_mode(string, optional): Whether matching content is only observed or actively enforced. -
direction(string, optional): Input/output classification hint stored with the guardrail. Guardrail execution still followshook_point; changing this value does not move evaluation to a different lifecycle hook.
Responses
201: Createdguardrail(object, required): A configured guardrail as returned by the API.
A guardrail inspects traffic only where an attachment puts it. Creating one attaches it to nothing, so it is enforced nowhere until you POST a guardrail attachment naming its scope; the console does this for you when you pick a scope on the create form. An enabled guardrail with no attachment is a valid state — its scope target may have been deleted — and the gateway treats it as inspecting no traffic rather than as applying everywhere.
-
guardrail.id(string, required): Guardrail ID within the environment. -
guardrail.env_id(string, required): Environment that owns the guardrail. -
guardrail.name(string, required): Human-readable guardrail name, unique within the environment. -
guardrail.enabled(boolean, required): Whether connected gateways evaluate this guardrail. -
guardrail.hook_point(string, optional): Where in the request lifecycle the guardrail executes. This is the runtime control;directionis only metadata. -
guardrail.kind(string, required): Guardrail provider kind. Fixed at creation. -
guardrail.fail_open(boolean, optional): When the remote guardrail provider cannot complete its check, allow (true) or block (false) the request. Defaults to false — an unchecked request is not released. No-op for kind=keyword. -
guardrail.config(object, optional): Kind-specific configuration. Shape is validated server-side against the guardrail catalog; secrets are redacted here.
Kinds that store a secret replace it with a server-computed
summary of what is held: api_key_set,
access_key_secret_set, aws_credentials.secret_set or
secret_names. These are read-only projections. You may send
them straight back on create or update — the value is
accepted when it matches what the server holds, so a
read-modify-write round-trip works unchanged — but they never
write anything: a value that disagrees is rejected with 400
rather than silently ignored. To change the underlying
secret, send the secret field itself (api_key,
access_key_secret, aws_credentials.secret_access_key, or
secrets).
-
guardrail.family(string, optional): Dashboard grouping metadata (not sent to the data plane). -
guardrail.provider(string, optional): Provider metadata used to select the guardrail configuration form. -
guardrail.check_type(string, optional): Check-category metadata used to select the guardrail configuration form. -
guardrail.enforcement_mode(string, optional): Whether matching content is only observed or actively enforced. -
guardrail.direction(string, optional): Input/output classification hint stored with the guardrail. Guardrail execution still followshook_point; changing this value does not move evaluation to a different lifecycle hook. -
guardrail.created_at(string, optional): RFC3339 time when the guardrail was created. -
guardrail.updated_at(string, optional): RFC3339 time when the guardrail was last updated. -
warnings(array, optional): Present on create and update when some data plane nodes in the environment run a gateway version that will not execute part of the saved configuration — a custom patternreplacement, for example, makes an older gateway drop the whole guardrail, which then stops enforcing there entirely. Never present on reads. -
warnings[].code(string, required): How affected nodes treat the saved resource.field_ignored: the resource stays in service on those nodes but the named field has no effect there — beware when the field is restrictive, since the restriction is silently not enforced.row_rejected: those nodes refuse the whole resource, so it stops serving there entirely (or, if a previously accepted version exists, they keep serving the old values). -
warnings[].field(string, required): Dot-separated path of the field that triggered the warning, as delivered to gateway nodes. -
warnings[].min_dp_version(string, required): Oldest gateway version that fully executes the field. The literal valueunreleasedmeans no released gateway version executes it yet. -
warnings[].affected_dp_count(integer, required): Number of currently registered nodes in the environment running an older gateway version thanmin_dp_version. -
warnings[].affected_dp_versions(array, required): Distinct gateway versions reported by the affected nodes, capped at five entries. Nodes that report no version appear asunknown. -
400: Request body or parameters failed validation. -
error(object, required): Error details. -
error.code(string, required): Machine-readable identifier. Examples:UNAUTHENTICATED,INVALID_REQUEST,MASTER_KEY_UNSET,INTERNAL. -
error.message(string, required): Human-readable explanation; safe to surface to operators. -
401: Missing or invalid bearer. Response fields (application/json): identical toPOST /environments/{env_id}/guardrails, response 400 above. -
403: Authenticated request is not permitted. Response fields (application/json): identical toPOST /environments/{env_id}/guardrails, response 400 above. -
404: Resource not found. Response fields (application/json): identical toPOST /environments/{env_id}/guardrails, response 400 above. -
409: Request conflicts with current resource state. Response fields (application/json): identical toPOST /environments/{env_id}/guardrails, response 400 above.
cURL
curl -X POST '$AISIX_CP/environments/{env_id}/guardrails' -H 'Authorization: Bearer $AISIX_TOKEN'