airs gateway
airs gateway (the TypeScript CLI's aigateway) manages and observes Prisma AIRS AI
Gateway: workspaces and scopes, telemetry, the inventory and admin guardrails, writes,
inference and the environment report.
Reads
airs gateway workspaces list # the data plane: workspaces you are scoped to
airs gateway workspaces list --all --output json # admin plane, active and archived
airs gateway workspaces get ws-main-a-349e0e --plane admin
airs gateway scopes list
airs gateway scopes get ws_production_bx7qw0 --output json
airs gateway telemetry cost --workspace "Main A" --days 30 # a display name: needs the admin grant too
airs gateway telemetry requests --workspace ws-main-a-349e0e --start 2026-10-01T00:00:00Z --end 2026-10-02T00:00:00Z
airs gateway telemetry group-by model --workspace ws-main-a-349e0e --columns cost,total_tokens
airs gateway telemetry logs list --workspace ws-main-a-349e0e --page-size 20 --current-page 1
airs gateway configs list --workspace 16f7e90d-382a-4e78-b577-1b01eb5f8297
airs gateway providers get 2c1e5f0a-7d43-4b8e-9a51-0f2d3c4b5a69 --output json
airs gateway integrations providers # the catalog slugs
airs gateway audit-logs list --days 1 --reveal-sensitive
airs gateway organisations auth-settings get # the selected tenant's TSG
airs gateway admin-guardrails list --page-size 50 --current-page 0
The gateway commands use the tenant's gatewayDataEndpoint, gatewayAdminEndpoint and
iamEndpoint (else the SDK defaults) with the management OAuth identity and the x-tsg-id
header. Every telemetry command resolves --workspace (a slug, UUID or unique display name)
over the data plane, then the admin plane's active and archived lists, and refuses a reference
nothing matches before any telemetry request. A slug or UUID the data plane lists needs
only the data-plane grant; a display name also reads the admin-plane lists (an exact slug there
wins over a name) and so needs the admin grant too, and a 403 on those lists says to use the
slug or UUID. --start and --end take ISO-8601 times
with Z or an offset and are sent in UTC whatever the host's time zone; --days with --start
is refused. Every argument check runs before the tenant is read (exit 2). table
prints a table and an empty json list prints []; acknowledgements, warnings and the 403
grant hint go to stderr, and a list the service says is incomplete is printed with a
warning. Every gateway document goes through one set of rules in every format: the SDK's secret paths for the resource; members whose names are credential
names in any case or separator (clientSecret, API KEY, api.key, db_pwd, db_pass,
GITHUB_PAT, refreshTokens, tokenvalue, account_key, access_keys, basic_auth,
signature, passcode, otp, a Vault secret_id, any name carrying a credential word such as
adminpassword: every name TypeScript masks but listed identifiers, references, token counts, key
names and lists of them (metadataKeys, virtual_keys), guardrail settings and tokenizer, a secret mapping's secret_key, and a name whose last
words describe a credential, such as user_api_key_count, user_api_key_ttl, api_key_name,
token_type, token_expires_at or token_url, which print); the values of header maps (headers and every *_headers name) and of
{key, value}, {name, value} and {header, value} pairs (header and environment lists) but the
safe headers'; the SDK's credential members; credentials inside a JSON text, and the whole of a text
that is shaped as JSON but does not parse; PEM private keys under any name; the filter-boundaries
data; and any string that carries a value withheld elsewhere. Each is printed as [withheld].
Inside any string, under any name, the text rules recognise exactly these shapes:
- URLs: the userinfo, query and fragment of every
scheme://URL, at the start of the string or inside prose (connect ECONNREFUSED https://[withheld]@db/x?[withheld]); the userinfo runs to the URL's last@, so a password holding/,?or#is withheld whole. - Authorization schemes: the word after
Basic,BearerorTokenwhen it looks like a credential or a password (or, afterBasic, is base64 ofuser:password), also with the scheme joined to its header name (Authorization: Bearer [withheld],Authorization:Bearer [withheld]). - Header lines: the value after a credential header name written with a
-(orAuthorization,Cookie) and a:(curl -H 'X-Api-Key: [withheld]',-H "api-key:[withheld]",Authorization: [withheld]). key=valueforms: the value of a credential-named key (Password=[withheld];,client_secret=[withheld],--token=[withheld],SharedAccessSignature=[withheld]), and a token-like value undertoken=orkey=. In a connection string a credential's value runs to the next;(Password=[withheld];forPassword=p@ss w0rd;) and an ODBC braced value to its closing}(PWD=[withheld];forPWD={p@ss;w0rd};); spaces around the=are read after a credential name only (password = [withheld],aws_secret_access_key = [withheld]).
A long word after the ordinary words token or basic in prose (token gpt-4o-mini-2024-07-18 quota exceeded) is withheld in that text only, so the same model id elsewhere stays printed; so is a
credential key's value that only says it is absent or masked, or is a short word of letters and
digits (auth=none, Password=true, Pwd=****, auth=oauth2), which never withholds none,
true or oauth2 in another row. A credential name's value that is one short word (under 8
characters of letters, digits and -, _, ., / or :: Bearer, hunter2), a placeholder or
mask, a state, mode or grant-type word (disabled, required, anonymous,
oauth2_client_credentials), a credential kind repeated by a sibling *_type or *_mode
({"auth": "password", "auth_type": "password"}), or a timestamp is withheld in place only, so the
same word elsewhere is printed; a longer value (dragonfly) is withheld wherever it is echoed. A number and an empty string under a
credential name, key, token or a credential header ({"password": 12345678},
{"headers": {"Authorization": 12345678}}, {"key": "password", "value": 12345678}) are withheld,
as TypeScript masks them on the inventory reads, and a number of 8 or more digits is withheld
wherever it is echoed. null and booleans are printed under every name, and so are numbers under
token-count names and other headers (prompt_tokens: 5, x-retries: 3) and price or usage
objects under token-count names (prompt_tokens, request_token); an object under a credential
name is withheld whole. Names that describe a credential print their values (user_api_key_count,
user_api_key_ttl, token_type, token_expires_at), and so do fingerprints (api_key_last8,
api_key_hint, token_prefix) unless the value looks like a credential itself. Model output (inference) gets the URL and scheme rules only. The
rules do not recognise, and print: a bare secret under a neutral member name with none of the
shapes above around it; a name: value line whose name is not a credential header
(password: hunter2x); key = value with spaces under a name that is not a credential name
(token = …); and a credential in prose with no scheme, header or = before it. Review output
before sharing it.
The inventory reads print TypeScript's generic tables (Field │ Value for one record) with those
rules applied: API key material, provider keys and model configs, integration and MCP secrets and
custom headers, SCIM tokens and SSO client secrets, deployment credentials and environment lists,
plugin credentials, service-account JSON, OAuth metadata and secret-manager settings at any depth,
the provider keys and service accounts inside a config's config text, and the
organisations info settings are withheld; masked_* fingerprints are printed. The
guardrail catalog prints its parameter schemas as sent, but for a non-empty default, const,
enum or examples under a credential-named parameter (an empty one, "" or [], prints).
--reveal-sensitive is refused on api-keys, providers get and auth-settings get; on
audit-logs list it shows the request body, headers and query as JSON with their credentials
still withheld, a secret reference's whole auth_config included (they are withheld by default). --tsg-id defaults to the selected
tenant's TSG and another value is refused. Ids are checked as UUIDs before the tenant; integrations models list lists the models TypeScript's generic list never showed.
Writes
airs gateway workspaces create --name Production --scope-name ws_production_bx7qw0
airs gateway workspaces update Production --description 'Production workloads, us-east'
airs gateway workspaces archive ws-produc-985697 --force
airs gateway scopes bind ws_production_bx7qw0 --workspace ws-produc-985697
airs gateway configs create --name routing --workspace <uuid> --file config.json --set config.retry.attempts=3
airs gateway api-keys service create --name ci --scopes completions.write --type service --workspace <uuid> --secret-output ./ci-key.json
airs gateway api-keys service rotate <id> --secret-output ./rotated.json
airs gateway integrations create --ai-provider openai --name openai-prod --slug openai-prod --key-stdin < provider.key
airs gateway integrations workspaces set <id> --workspace-binding ws-main-a-349e0e=true --preserve-existing
airs gateway deployments update <id> --rotate-auth true --secret-output ./edge-credentials.json
airs gateway admin-guardrails mcp-servers sync <guardrail-id> --file mappings.json --force
Every write is sent once: a 401 is replayed once after a fresh token, a 403 never, and a write
whose outcome is unknown (a 5xx, a timeout, a dropped connection) or whose answer cannot be read
says so with a hint, and nothing is re-sent. workspaces create creates the IAM scope,
the workspace, the binding and reads the workspace back; it deletes the scope it made only after
a rejected workspace create and names every partial state. Request bodies come from
--file (one JSON object, YAML refused) < the named flags < --set/--set-string; no
error echoes a value; --organisation-id and --tsg-id default to the selected tenant's
TSG and another value is refused. One-time credentials (new API keys, rotated keys,
deployment credentials) go only to a new 0600 --secret-output file, reserved before the
request and never overwritten; --show-secret is refused. Deletes, archives (a
deployments update --status archived too), rotations, replacements, tenant-wide updates and
updates that replace a resource's authentication (a deployment's --auth-settings, an MCP
integration's --auth-type or credentials) ask for confirmation (--force skips it; without a terminal they are refused); deletes print nothing on stdout and every write acknowledges on stderr. Provider credentials come from --key-file, piped --key-stdin or a hidden prompt;
inline --key, --scim-token, --credential and --header values are accepted with a warning. An interrupted write says what may have changed.
Inference and the report
airs gateway inference chat "Summarise our retry policy" # the text
airs gateway inference chat --file request.json --model openai__gpt-x --output json
airs gateway inference responses "Hi" --stream # text as it arrives
airs gateway inference responses "Hi" --stream --output json # one event per line (JSONL)
airs gateway inference embeddings "hello" --dimensions 256 --encoding float
airs gateway report --workspace ws-main-a-349e0e --output-file ./gateway-daily.html
airs gateway dashboard --workspace "Main A" --days 7 --strict --output-file - > weekly.html
gateway inference calls the runtime gateway with the tenant's gatewayInferenceApiKey as
x-portkey-api-key (no OAuth) on --endpoint or the tenant's gatewayInferenceEndpoint; the
model is --model, else the request file's, else gatewayInferenceModel (gatewayEmbeddingModel
for embeddings). No environment variable is read. Each call is sent once (model calls are
billed); --timeout bounds the whole request, the stream included. Model text is printed with its
line breaks and tabs and every other control character replaced, a registered secret withheld even
when split across stream events; table prints the answer's top level, yaml is refused; an
interruption says the request may have been processed and billed, exit 130/143.
gateway report (alias dashboard) reads 25 sources over one fixed window (the last --days, or
--start/--end with a time zone, sent in UTC): the tenant's workspaces, 17 telemetry charts, the
filter boundaries, the transaction logs page by page (--max-pages), the workspace's configs and
keys, the organisation and the guardrail catalog. It writes one self-contained HTML file (the red
team report's template: strict Content Security Policy, works offline) that is new, 0600 and never
overwritten, the default airs-gateway-report-<time>-<id>.html. It keeps aggregates only:
no workspace, key, user, model or URL. The destination and its directory are checked before any
request; --output and --debug are refused; a window outside the years
0000–9999 and zone-less times are refused. It exits 1 when no telemetry source could be
read, or with --strict when a source is incomplete.
Every flag
Every command and flag is in the command reference.