Rotate Caller API Key
POST /environments/{env_id}/api_keys/{api_key_id}/rotate
POST /environments/{env_id}/api_keys/{api_key_id}/rotateInteractive 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.
uuidCaller API key ID within the environment.
uuidResponse Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID/rotate" \ -H "Authorization: Bearer $AISIX_TOKEN"Rotated. The body carries the new plaintext bearer once; persist it on the caller side immediately.
{
"api_key": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"env_id": "3f917d0d-4dff-42f3-97c4-6a5455dfe8c2",
"display_name": "string",
"allowed_models": [
"758d9dd9-ab4c-4ea7-99f0-f43c6c03d118"
],
"allowed_agents": [
"string"
],
"allowed_routes": [
"string"
],
"mcp_access": {
"allow": [
"string"
],
"deny": [
"string"
]
},
"mcp_rate_limits": {
"property1": {
"rps": 1,
"rpm": 1,
"rph": 1,
"rpd": 1,
"concurrency": 1
},
"property2": {
"rps": 1,
"rpm": 1,
"rph": 1,
"rpd": 1,
"concurrency": 1
}
},
"rate_limit": {
"rps": 1,
"rpm": 1,
"rph": 1,
"rpd": 1,
"tpm": 1,
"tpd": 1,
"concurrency": 1
},
"team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
"jwt_subject": "string",
"jwt_provider": "string",
"expires_at": "2019-08-24T14:15:22Z",
"disabled": true,
"status": "active",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
},
"plaintext": "string",
"warnings": [
{
"code": "field_ignored",
"field": "string",
"min_dp_version": "string",
"affected_dp_count": 0,
"affected_dp_versions": [
"string"
]
}
]
}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"
}
}Complete operation details and schema variants
POST /environments/{env_id}/api_keys/{api_key_id}/rotate
Rotate Caller API Key
Replace the key's underlying bearer with a freshly generated value in one operation. The key resource is preserved — name, allowed models, rate limit, bindings, expiry deadline, and disabled state carry over; only the credential changes. The old plaintext stops authenticating, and the new plaintext is returned once in the rotate response. There is no request body.
Parameters
env_id(path, string, required): Environment ID that scopes the request.api_key_id(path, string, required): Caller API key ID within the environment.
Responses
-
200: Rotated. The body carries the new plaintext bearer once; persist it on the caller side immediately. -
api_key(object, required): Caller credential metadata. The plaintext bearer is returned only in the create response. -
api_key.id(string, required): Caller API key ID. -
api_key.env_id(string, required): Environment ID that owns this caller API key. -
api_key.display_name(string, required): Human-readable caller API key name. -
api_key.allowed_models(array, required): UUIDs of model resources in the same environment this key may address. Empty array denies every model. Granting a routing group / semantic router / ensemble authorizes requests addressed to that entry; its members stay unaddressable unless granted themselves. Granting a wildcard entry (display name containing a single*) authorizes every request whose model name matches the pattern — including a name that also exists as a separately registered, ungranted exact model (the glob grants access; the exact entry still serves the request). -
api_key.allowed_agents(array, optional): A2A agents this key may reach, as agent-name patterns.*grants every agent and an exact agent name grants a single agent. Absent grants no A2A agent access; access is explicit. Present only when at least one pattern is set. -
api_key.allowed_routes(array, optional): Passthrough routes this key may use, as route-name patterns.*grants every route and an exact route name grants a single route. Absent grants no passthrough-route access; access is explicit. Present only when at least one pattern is set. -
api_key.mcp_access(object, optional): The key's own layer of the MCP tool ACL, intersected with the environment and team layers. Absent means the key adds no constraint of its own. -
allOf variant 1
-
api_key.mcp_access.allow(array, required): Namespacedserver__toolpatterns this key allows (*,server__*, or an exactserver__tool). Each entry may use letters, digits,.,_,-, and*; other characters are rejected. An empty list leaves the key no MCP tool access;["*"]narrows nothing, which is what a key that only means to subtract tools sends alongsidedeny. -
api_key.mcp_access.deny(array, optional): Namespacedserver__toolpatterns removed from the key's effective grant, matched the same way asallow. Deny always wins over any allow, on any layer. -
api_key.mcp_rate_limits(object, optional): Per-MCP-server limits for this key, keyed by MCP server name. Present only when at least one server is limited. -
api_key.mcp_rate_limits.*.rps(integer, optional): Tool calls per second. -
api_key.mcp_rate_limits.*.rpm(integer, optional): Tool calls per minute. -
api_key.mcp_rate_limits.*.rph(integer, optional): Tool calls per hour. -
api_key.mcp_rate_limits.*.rpd(integer, optional): Tool calls per day. -
api_key.mcp_rate_limits.*.concurrency(integer, optional): Maximum in-flight tool calls to this MCP server. -
api_key.rate_limit(object, optional): Per-key rate limit.nullmeans no key-level limit. -
allOf variant 1
-
api_key.rate_limit.rps(integer, optional): Requests per second. -
api_key.rate_limit.rpm(integer, optional): Requests per minute. -
api_key.rate_limit.rph(integer, optional): Requests per hour. -
api_key.rate_limit.rpd(integer, optional): Requests per day. -
api_key.rate_limit.tpm(integer, optional): Tokens per minute. -
api_key.rate_limit.tpd(integer, optional): Tokens per day. -
api_key.rate_limit.concurrency(integer, optional): Maximum in-flight requests. -
api_key.team_id(string, optional): Team binding used for attribution and policy scope. -
api_key.user_id(string, optional): Organization member this key is attributed to — the membershipidfromGET /members, not that member'suser_id. -
api_key.jwt_subject(string, optional): External identity bound to this key for JWT authentication. When a request presents a valid JWT from the OIDC provider named injwt_provider, that provider's identity claim selects the key whosejwt_subjectequals it, and the request runs with this key's permissions, rate limits, and budget. Thejwt_providerandjwt_subjectpair is unique within the environment. -
api_key.jwt_provider(string, optional): Name of the OIDC provider permitted to assert this key'sjwt_subject. A token is only ever mapped to this key when issued by the named provider, so a second trusted provider cannot impersonate this identity. Set together withjwt_subject. -
api_key.expires_at(string, optional): Expiry deadline. Present only when set; absent for keys that never expire. Once the deadline passes, the gateway rejects the bearer with401. -
api_key.disabled(boolean, required): Administratively disabled. A disabled key is rejected by the gateway with401until re-enabled; the underlying bearer is preserved. -
api_key.status(string, required): Derived lifecycle state:disabledwins overexpired; a key isexpiredonceexpires_athas passed; otherwiseactive. -
api_key.created_at(string, required): Time when the caller API key was created. -
api_key.updated_at(string, required): Time when the caller API key was last updated. -
plaintext(string, required): The plaintext bearer the caller must include on gateway requests asAuthorization: Bearer <plaintext>. Persist this on the client side immediately. There is no recovery path on the server. -
warnings(array, optional): Data-plane compatibility warnings for this save, when any connected data plane predates a configured capability (e.g.allowed_routeson a pre-0.10.0 fleet). -
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}/api_keys/{api_key_id}/rotate, response 400 above. -
403: Authenticated request is not permitted. Response fields (application/json): identical toPOST /environments/{env_id}/api_keys/{api_key_id}/rotate, response 400 above. -
404: Resource not found. Response fields (application/json): identical toPOST /environments/{env_id}/api_keys/{api_key_id}/rotate, response 400 above.
cURL
curl -X POST '$AISIX_CP/environments/{env_id}/api_keys/{api_key_id}/rotate' -H 'Authorization: Bearer $AISIX_TOKEN'