List Passthrough Routes
GET /admin/v1/passthrough_routes
GET /admin/v1/passthrough_routesInteractive request editor loads with JavaScript.
Authorization
AdminBearer Admin key from config.admin.admin_keys.
In: header
Response Body
application/json
application/json
application/json
curl -X GET "http://127.0.0.1:3001/admin/v1/passthrough_routes"OK
[
{
"id": "string",
"revision": 0,
"value": {
"display_name": "string",
"enabled": true,
"forward_client_headers": [
"string"
],
"name": "string",
"provider_key_id": "string",
"timeout_ms": 1,
"hosts": [
"string"
],
"path_prefix": null,
"preserve_host": true,
"target_url": "string",
"identity_header": null,
"auth_header_name": "string",
"auth_mode": "anonymous",
"anonymous_key_id": "string",
"source_cidrs": [
"string"
],
"credential_mode": "forward_client"
}
}
]Missing or invalid admin key
{
"error_msg": "string"
}Configuration store operation failed
{
"error_msg": "string"
}Complete operation details and schema variants
GET /admin/v1/passthrough_routes
List Passthrough Routes
List explicit passthrough route resources.
Parameters
Responses
200: OK[].id(string, required): Resource ID, as assigned by the active resource source.[].revision(integer, required): Monotonic resource revision: the etcd mod_revision of the entry, or the load generation in file mode.[].value(object, required): Stored passthrough route configuration.- allOf variant 1
[].value.anonymous_key_id(string,null, optional): The API key this route's traffic runs as whenauth_modeisanonymous: itsallowed_routes, rate limits, budget and usage attribution all apply, so anonymous traffic keeps a stable, governable principal. Required foranonymous; ignored otherwise.[].value.auth_header_name(string,null, optional): Header carrying the gateway credential (API key or JWT) whenauth_modeisheader_key, e.g.x-aisix-api-key. LetsAuthorizationcarry the caller's own upstream credential. The header is stripped before forwarding. Lowercase-only so the forbidden credential-slot list in the coupling is exhaustive (matching is case-insensitive on the wire regardless). Required forheader_key; ignored otherwise.[].value.auth_mode(object, optional): How the gateway authenticates the caller on this route.- allOf variant 1
- oneOf variant 1: Standard gateway credential
- oneOf variant 2: Gateway credential in a dedicated header
- oneOf variant 3: Anonymous (bound principal)
[].value.credential_mode(object, optional): How the upstream credential is produced.- allOf variant 1
- oneOf variant 1: Inject the ProviderKey secret
- oneOf variant 2: Forward the caller's own credential
[].value.display_name(string, optional): Accepted as an alternative spelling ofname. Provide the label under exactly one of the two names.[].value.enabled(boolean, optional): Whether this route is active. A disabled route matches nothing.[].value.forward_client_headers(array, optional): Inbound client headers forwarded to the upstream even when this route would otherwise strip them, as single-*glob patterns matched case-insensitively against the header name ("authorization","x-trace-*"). Empty — the default — overrides no stripping.
A header the caller sends more than once is forwarded with every value preserved.
A route forwards the caller's headers by default, so this field only matters for the ones it removes: the ProviderKey's strip_headers under credential_mode: inject, and the slot the gateway consumed to authenticate the caller. Naming authorization under auth_mode: gateway_key therefore puts the caller's own credential back on the upstream request in place of the one this route would inject, never both — which is what lets an internal service that already authorizes on the end user's Authorization keep doing so unchanged.
A credential slot — authorization, proxy-authorization, x-api-key, api-key, x-goog-api-key, cookie, and the AWS SigV4 trio x-amz-security-token / x-amz-date / x-amz-content-sha256 — and traceparent / tracestate are forwarded only when a pattern names them exactly. A glob such as "*" or "x-*" is a statement about the operator's own headers, not consent to hand a third party the caller's credential or to graft the caller's trace onto that party's telemetry, so a broad pattern overrides the rest of the strip set and leaves those alone.
This route's own auth_header_name and identity_header are read the same way. Both are slots this route chose rather than ones the gateway owns — under auth_mode: header_key the first carries the gateway credential the caller authenticated with, and the second carries an end-user identity this route records and strips — so a glob does not sweep either, and a pattern that names one in full forwards it.
Headers whose forwarding would break the exchange rather than change who it comes from are stripped whatever the patterns say: host, content-length, the hop-by-hop headers that describe the caller's own connection, and the gateway's x-aisix-* namespace.
[].value.hosts(array,null, optional): InboundHostvalues this route serves (the forward-proxy entry: a TLS-terminating device delivers plaintext traffic with the original host, e.g.api.githubcopilot.com). Matched case-insensitively, ignoring any:portsuffix; a leading*.wildcard matches exactly one extra label (*.githubcopilot.commatchesproxy.githubcopilot.com). Host-matched requests keep their full path (no prefix stripping unlesspath_prefixalso matched).[].value.identity_header(string,null, optional): Optional header carrying the end-user identity injected by the upstream network device (e.g.x-aisix-user). Its value is recorded on the usage event for per-employee audit attribution and stripped before forwarding. Lowercase-only so the forbidden credential-slot list in the coupling is exhaustive; credential-bearing names (authorization,cookie, …) are rejected outright — their value on the usage event would be credential retention, not identity.[].value.name(string, optional): Operator-facing label, unique within the gateway. Referenced by API keys'allowed_routesglobs and used for usage attribution.[].value.path_prefix(string,null, optional): Gateway path prefix this route serves, e.g./passthrough/openai. Must start with/.
How the prefix is treated depends on the target shape: a target_url route MOUNTS at the prefix, so it is stripped before the remainder is joined to the target base; a preserve_host route MIRRORS an upstream that owns its own path space, so the prefix only selects which requests the route claims and the complete path is forwarded unchanged.
A route WITHOUT hosts must not claim a reserved gateway namespace (/v1, /mcp, /a2a, health probes) — the typed routes would shadow it. A route WITH hosts may use any prefix: host-matched requests dispatch ahead of the typed routes, which is what lets a forward proxy relay an upstream's own namespace (e.g. Copilot's /mcp/... on its chat host). At least one of path_prefix / hosts is required; when both are set the request must satisfy both.
[].value.preserve_host(boolean, optional): Derive the target from the request's ownHostheader (https://<host>), for forward-proxy routes that fan one route out over several official hosts. Only legal whenhostsis set — the matched allowlist is what makes the derived target non-attacker- controlled (SSRF guard).[].value.provider_key_id(string,null, optional): ProviderKey whose secret is injected upstream whencredential_modeisinject(per-provider auth shape:x-api-key+anthropic-versionfor Anthropic,Authorization: Bearerotherwise; itsstrip_headersand TLS settings apply). Required forinject; forbidden forforward_client.[].value.source_cidrs(array,null, optional): Client source CIDRs allowed to use this route. Required (non-empty) whenauth_modeisanonymous— network reachability is the only gate left in front of the anonymous principal. Optional hardening for the other modes; unset means no route-level restriction.[].value.target_url(string,null, optional): Explicit upstream base URL, e.g.https://api.openai.com. The matched request's remainder path and query are appended. Exactly one oftarget_url/preserve_hostmust be configured.[].value.timeout_ms(integer,null, optional): Maximum time, in milliseconds, for the upstream exchange. Bounds the response-header phase and any non-SSE body read, but never a healthy SSE relay (which ends with the upstream stream or the client hanging up). When omitted, the gateway default request timeout applies the same way.- allOf variant 1
- anyOf variant 1: Path-prefix match
- anyOf variant 2: Host match
- allOf variant 2
- allOf variant 3
- allOf variant 4
- allOf variant 5
- oneOf variant 1: Explicit target URL
- oneOf variant 2: Preserve inbound host
[].value.preserve_host(object, required): Set when the route derives its target from the inbound Host instead of target_url.- allOf variant 6
- allOf variant 7
- allOf variant 8
- allOf variant 9
- allOf variant 10
- allOf variant 11
- allOf variant 12: auth_header_name only in header_key mode
- allOf variant 13: anonymous_key_id only in anonymous mode
- allOf variant 14
- allOf variant 15
- anyOf variant 1: name
- anyOf variant 2: display_name
401: Missing or invalid admin keyerror_msg(string, required): Human-readable error message.500: Configuration store operation failed Response fields (application/json): identical toGET /admin/v1/passthrough_routes, response 401 above.
cURL
curl -X GET 'http://127.0.0.1:3001/admin/v1/passthrough_routes'