Create Passthrough Route
POST /environments/{env_id}/passthrough_routes
POST /environments/{env_id}/passthrough_routesInteractive 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 an explicit passthrough route. Coupling rules (enforced
here and identically in the gateway's resource schema): at
least one of path_prefix / hosts; exactly one of
target_url / preserve_host: true (the latter only together
with hosts); header_key ⇒ auth_header_name; anonymous
⇒ anonymous_key_id + non-empty source_cidrs; inject ⇒
provider_key_id, forward_client ⇒ no provider_key_id.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "$AISIX_CP/environments/$ENV_ID/passthrough_routes" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "copilot-chat", "hosts": [ "api.githubcopilot.com", "*.individual.githubcopilot.com" ], "preserve_host": true, "auth_mode": "header_key", "auth_header_name": "x-aisix-api-key", "credential_mode": "forward_client", "identity_header": "x-aisix-user" }'Created
{
"passthrough_route": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"env_id": "3f917d0d-4dff-42f3-97c4-6a5455dfe8c2",
"name": "string",
"path_prefix": "string",
"hosts": [
"string"
],
"target_url": "string",
"preserve_host": false,
"auth_mode": "gateway_key",
"auth_header_name": "string",
"anonymous_key_id": "cf032c4c-881f-492e-aa11-fcbf5714649c",
"source_cidrs": [
"string"
],
"credential_mode": "inject",
"provider_key_id": "f265db88-9bcc-4e5b-add5-bfd9a815465c",
"identity_header": "string",
"timeout_ms": 1,
"enabled": true,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
},
"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}/passthrough_routes
Create Passthrough Route
Create an explicit passthrough route: a binding from a gateway
entry — a path_prefix on the gateway's own URL space, an
inbound hosts allowlist (forward-proxy traffic delivered with
its original Host), or both — to one upstream target, forwarded
without protocol translation. The route carries its own gateway
authentication mode and upstream credential handling; callers
additionally need the route's name granted in their API key's
allowed_routes patterns. At least one match dimension
(path_prefix or hosts) is required. Exactly one target shape
is required: target_url, or preserve_host: true (which
derives https://<host> from the matched inbound host and is
only accepted together with hosts). auth_mode: header_key
requires auth_header_name; auth_mode: anonymous requires
anonymous_key_id and a non-empty source_cidrs.
credential_mode: inject (the default) requires
provider_key_id; credential_mode: forward_client forbids it.
The route name is unique within the environment and cannot be
changed after creation.
Parameters
env_id(path, string, required): Environment ID that scopes the request.
Request body
Content type: application/json
-
name(string, required): Route name, unique within the environment. Fixed at creation; referenced by API keys'allowed_routes. -
path_prefix(string, optional): Gateway path prefix to serve (segment-boundary match; atarget_urlroute strips it before the remainder joins the target, apreserve_hostroute forwards the complete path). Reserved gateway namespaces (/v1,/mcp,/a2a,/admin,/livez,/readyz,/metrics) are rejected on a route withouthosts— the gateway's own endpoints would shadow it. A route that also matches onhostsmay claim any prefix: host-matched requests dispatch ahead of the typed endpoints, which is what lets a forward proxy relay an upstream's own namespace. -
hosts(array, optional): Inbound Host allowlist to serve.*.wildcards match one extra label and need at least two literal labels (*.example.com, never*.com). -
target_url(string, optional): Explicit upstream base URL. -
preserve_host(boolean, optional): Derive the target from the matched inbound host instead oftarget_url. Only accepted together withhosts. -
auth_mode(object, optional): Gateway authentication mode for this route. -
allOf variant 1
-
auth_header_name(string, optional): Lowercase gateway-credential header forheader_keymode; credential-bearing names are rejected, and so is setting this on any otherauth_mode. -
anonymous_key_id(string, optional): Environment API key anonymous traffic runs as (required foranonymousmode, rejected on any other). The key must exist in this environment. -
source_cidrs(array, optional): Source CIDRs allowed to use the route. Required foranonymousmode; optional otherwise. -
credential_mode(object, optional): Upstream credential handling for this route. -
allOf variant 1
-
provider_key_id(string, optional): Provider key to inject (required forinjectmode; must be visible to this environment; forbidden forforward_client). -
identity_header(string, optional): Lowercase end-user identity header recorded asclient_identity; credential-bearing names are rejected. -
timeout_ms(integer, optional): Upstream exchange bound in milliseconds (response-header phase and non-SSE body reads; never a healthy SSE relay). -
enabled(boolean, optional): Whether the route is active on creation.
Responses
201: Createdpassthrough_route(object, required): An explicit passthrough binding from a gateway entry to one upstream target. Callers additionally need the route's name granted by their API key'sallowed_routespatterns.
The body envelope (OpenAI-compatible chat / completions / Responses, or opaque) is not configured: the gateway detects it per request from the body's top-level keys, and guardrail extraction, audit capture, and token-usage recording follow the detection. Bodies are always relayed verbatim; SSE upstream responses are always relayed incrementally.
-
passthrough_route.id(string, required): Unique passthrough route ID. -
passthrough_route.env_id(string, required): Environment the route belongs to. -
passthrough_route.name(string, required): Route name, unique within the environment and fixed at creation. Referenced by API keys'allowed_routespatterns and recorded on usage events for attribution. -
passthrough_route.path_prefix(string, optional): Gateway path prefix this route serves (segment-boundary match:/copilotmatches/copilotand/copilot/x, never/copilotx). The prefix is stripped before the remainder joins the target URL. Must not claim a reserved gateway namespace (/v1,/mcp,/a2a,/admin,/livez,/readyz,/metrics). At least one ofpath_prefix/hostsis required; when both are set a request must satisfy both. -
passthrough_route.hosts(array, optional): Inbound Host values this route serves — the forward-proxy entry, where a TLS-terminating device delivers plaintext traffic with its original Host. Matched case-insensitively, ignoring any:portsuffix. A leading*.wildcard matches exactly one extra label and must keep at least two literal labels (*.githubcopilot.comis accepted;*.comand a bare*are rejected). Host-matched requests keep their full path unlesspath_prefixalso matched. -
passthrough_route.target_url(string, optional): Explicit upstream base URL; the matched remainder path and query are appended (a trailing/v1on the target and a leadingv1/on the remainder de-duplicate). Exactly one oftarget_url/preserve_host: truemust be configured. -
passthrough_route.preserve_host(boolean, required): Derive the target from the matched inbound host (https://<host>), for forward-proxy routes fanning one route over several official hosts. Only accepted together withhosts— the allowlist is what bounds the derived target. -
passthrough_route.auth_mode(object, required): How the gateway authenticates callers of this route.header_keyrequiresauth_header_name;anonymousrequiresanonymous_key_idand a non-emptysource_cidrs. -
allOf variant 1
-
passthrough_route.auth_header_name(string, optional): Lowercase header carrying the gateway credential whenauth_modeisheader_key(for examplex-aisix-api-key); stripped before forwarding. Rejected on any otherauth_mode— the gateway never consults it there. Credential-bearing names (authorization,proxy-authorization,cookie,set-cookie,x-api-key) are rejected. -
passthrough_route.anonymous_key_id(string, optional): The environment API key this route's traffic runs as whenauth_modeisanonymous. Itsallowed_routesgrant, rate limits, budget, and usage attribution apply unchanged, so anonymous traffic keeps a stable, governable principal. Rejected on any otherauth_mode— the gateway never consults it there. -
passthrough_route.source_cidrs(array, optional): Client source CIDRs allowed to use this route. Required (non-empty) whenauth_modeisanonymous; optional hardening for the other modes. Unset means no route-level source restriction. -
passthrough_route.credential_mode(object, required): How the upstream credential is produced.inject(the default) requiresprovider_key_id;forward_clientforbids it. -
allOf variant 1
-
passthrough_route.provider_key_id(string, optional): Provider key whose secret is injected upstream whencredential_modeisinject; its header-strip list and TLS settings apply to the route's traffic. The provider key must be visible to this environment. -
passthrough_route.identity_header(string, optional): Optional lowercase header carrying the end-user identity injected by the upstream network device (for examplex-aisix-user). Its value is recorded on usage events asclient_identityfor per-employee audit attribution and stripped before forwarding. Credential-bearing names are rejected. -
passthrough_route.timeout_ms(integer, optional): Upstream exchange bound in milliseconds. Bounds the response-header phase and any non-SSE body read, never a healthy SSE relay. When omitted, the gateway's default request timeout applies the same way. -
passthrough_route.enabled(boolean, required): Whether the route is active. A disabled route matches nothing. -
passthrough_route.created_at(string, required): Creation timestamp. -
passthrough_route.updated_at(string, required): Last update timestamp. -
warnings(array, optional): Data-plane compatibility warnings for this save, when any connected data plane predates a configured capability. -
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}/passthrough_routes, response 400 above. -
403: Authenticated request is not permitted. Response fields (application/json): identical toPOST /environments/{env_id}/passthrough_routes, response 400 above. -
404: Resource not found. Response fields (application/json): identical toPOST /environments/{env_id}/passthrough_routes, response 400 above. -
409: Request conflicts with current resource state. Response fields (application/json): identical toPOST /environments/{env_id}/passthrough_routes, response 400 above.
cURL
curl -X POST '$AISIX_CP/environments/{env_id}/passthrough_routes' -H 'Authorization: Bearer $AISIX_TOKEN'