Create Caller API Key
POST /environments/{env_id}/api_keys
POST /environments/{env_id}/api_keysInteractive 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 a caller credential and its model, MCP, identity, and rate-limit bindings. The plaintext bearer is returned only in the create response.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "string", "allowed_models": [ "758d9dd9-ab4c-4ea7-99f0-f43c6c03d118" ] }'Created. The body carries the 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"
}
}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}/api_keys
Create Caller API Key
Create a caller credential for an environment. The plaintext bearer is returned once in the create response and cannot be recovered later.
Parameters
env_id(path, string, required): Environment ID that scopes the request.
Request body
Content type: application/json
-
display_name(string, required): Human-readable caller API key name. -
allowed_models(array, required): UUIDs of model resources in the target 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). -
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. Omit or send an empty array to grant no A2A agent access. Each entry may use letters, digits,.,_,-, and*; other characters are rejected. -
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. Omit or send an empty array to grant no passthrough-route access. Each entry may use letters, digits,.,_,-, and*; other characters are rejected. -
mcp_access(object, optional): The key's own layer of the MCP tool ACL, intersected with the environment and team layers. Omit for a key that adds no constraint of its own — but note that a key with no layer anywhere has no MCP tool access, since access is granted explicitly. -
allOf variant 1
-
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. -
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. -
mcp_rate_limits(object, optional): Per-MCP-server limits for this key, keyed by MCP server name. Each server named here gets its own counter, so exhausting one server's allowance leaves the others untouched, andrate_limitstill applies on top. Servers that are not named are bounded byrate_limitalone. A name that matches no registered MCP server is accepted and takes effect if a server is later registered under it. -
mcp_rate_limits.*.rps(integer, optional): Tool calls per second. -
mcp_rate_limits.*.rpm(integer, optional): Tool calls per minute. -
mcp_rate_limits.*.rph(integer, optional): Tool calls per hour. -
mcp_rate_limits.*.rpd(integer, optional): Tool calls per day. -
mcp_rate_limits.*.concurrency(integer, optional): Maximum in-flight tool calls to this MCP server. -
rate_limit(object, optional): Per-key rate limit. -
allOf variant 1
-
rate_limit.rps(integer, optional): Requests per second. -
rate_limit.rpm(integer, optional): Requests per minute. -
rate_limit.rph(integer, optional): Requests per hour. -
rate_limit.rpd(integer, optional): Requests per day. -
rate_limit.tpm(integer, optional): Tokens per minute. -
rate_limit.tpd(integer, optional): Tokens per day. -
rate_limit.concurrency(integer, optional): Maximum in-flight requests. -
team_id(string, optional): Team binding used for attribution and policy scope. -
user_id(string, optional): Organization member this key is attributed to, given as the membershipidfromGET /members— not that member'suser_id, which is a different identifier and is rejected here as an unknown member. Binding a key attributes its traffic to the member and brings the member's limits and budgets into scope. Whenteam_idis also set, the member must belong to that team. -
key(string, optional): Caller-supplied plaintext bearer. The AISIX control plane generates one when this field is not supplied. The value is trimmed, stored as a SHA-256 hash, and returned only once in the create response. -
jwt_subject(string, optional): External identity bound to this key for JWT authentication, matched against the identity claim of tokens issued by the OIDC provider named injwt_provider. Set together withjwt_provider; the pair is unique within the environment. -
jwt_provider(string, optional): Name of the OIDC provider permitted to assert this key'sjwt_subject. Required whenjwt_subjectis set. -
expires_at(string, optional): Expiry deadline. Omit or sendnullfor a key that never expires. Once the deadline passes, the gateway rejects the bearer with401.
Responses
-
201: Created. The body carries the 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, response 400 above. -
403: Authenticated request is not permitted. Response fields (application/json): identical toPOST /environments/{env_id}/api_keys, response 400 above. -
404: Resource not found. Response fields (application/json): identical toPOST /environments/{env_id}/api_keys, response 400 above. -
409: Request conflicts with current resource state. Response fields (application/json): identical toPOST /environments/{env_id}/api_keys, response 400 above.
cURL
curl -X POST '$AISIX_CP/environments/{env_id}/api_keys' -H 'Authorization: Bearer $AISIX_TOKEN'