Skip to main content
A Portkey gateway becomes a TrustGuard collector by adding one guardrail check that calls /v1/evaluate before the upstream model call and again on the response. Every application already routing through the gateway is covered, with no client changes. There are two ways to wire it. The native neuraltrust plugin runs inside the gateway, so it holds the request body and can apply transform — it is the only one of the two that can redact. The Bring-Your-Own-Guardrails webhook works on any Portkey deployment today, including Portkey Cloud, but its contract is a boolean, so transform collapses to allow or deny. This page covers only the Portkey connection. Other gateways: TrustGate, LiteLLM, Kong, Apigee, Azure APIM.

Coverage

Ask — the integration maps the verdict onto a boolean, so an ask gate is allowed and recorded. Write the rule as Block if you need a hard stop. Use it when your apps already reach models through a Portkey config and you want one policy for all of them. Not when you do not control the gateway deployment, or you need redaction on streamed responses — only TrustGate inspects a stream. Limits. Redaction is conditional twice over: it needs the native plugin, which is not in a released Portkey version, and on the output side it applies to non-streaming completions only. The webhook does not redact at all. Tool declarations and tool calls are evaluated where Portkey populates them and a transformed tool call is written back, but every verdict is request-level: a block stops the whole request rather than one tool. Also. deny: true on the hook is what makes a block enforceable. Without it Portkey records the failed check and returns the request anyway. Full comparison: Coverage.

Before you start

Keep the policy in Report mode for the first rollout. Report downgrades every rule to report, so findings appear in Activity without breaking traffic. Switch to Enforce once the finding volume looks right — see Policies.
The native neuraltrust plugin is contributed in Portkey-AI/gateway#1772 and is not in a released Portkey version yet, so it is unavailable on Portkey Cloud. Until it ships, use the BYOG webhook below, which works on every deployment.

1. Enable the plugin

Add neuraltrust to plugins_enabled in the gateway’s conf.json:
Do not run npm run build-plugins to register it. That command regenerates plugins/index.ts from plugins_enabled, and because the shipped registry lists more plugins than conf.json does, running it silently drops every plugin missing from your list — eleven of them on a stock checkout. Add the import and the registry entry by hand instead.
Credentials do not belong in conf.json. They go on the check, so one gateway can route different routes to different collectors.

2. Attach the check to your config

The check id is neuraltrust.evaluate, and it runs on both hooks. Send this as a saved config or in the x-portkey-config header:
Declaring only one of the two hooks leaves that phase of your policy unused. session_id is picked up from request metadata (session_id, or _session_id) when present, so Activity groups turns the way your application does.

3. Know how each verdict lands

deny is what turns a failed check into enforcement: transform is written back in the shape the request came in: chat messages, a completion prompt, or Anthropic messages plus a top-level system. A transformed_payload.input string redacts the current text instead.
A transform that cannot be applied safely fails closed rather than forwarding unmasked content. That covers a missing payload, a message list shorter than the request, a changed role, a rewritten tool name or id, and a non-text content part. Silently forwarding a half-masked prompt while the console shows a successful transform is the worst available outcome, so it is not an option.
Only choices[0] is scanned and rewritten. Extra completions from n > 1 are left alone, which matches Portkey’s own shared content helpers.

4. Choose fail-open or fail-closed

This is the setting to read carefully, because the plugin deliberately disagrees with the engine’s default. Portkey treats a check as passing when it returns a verdict or when it errored and failOnError is not set — and failOnError defaults to false. An unreachable guardrail reported as an error would therefore be forgiven, and traffic would flow uninspected. So the plugin reports an unusable verdict as verdict: false with no error attached, which the engine cannot forgive. Scope is narrow: fail_open covers only connect errors, timeouts, and HTTP 502/504. Everything else fails closed even when you asked for fail_open:
  • HTTP 401/403, and HTTP 503 entitlement failures
  • any other 4xx or 5xx, including 429
  • a 200 that is not JSON, or that carries an unknown verdict
  • a transformed_payload that cannot be applied safely
  • a missing apiKey, and any unexpected error inside the plugin
fail_open means an outage of the guardrail quietly becomes an outage of your controls rather than of your service, and on this gateway it is quieter than most: the request succeeds and the explanation appears only in hook_results. Alert on it, or leave the default.

5. Verify

A block is visible from the HTTP response, so one call is the whole check:
With a jailbreak rule in Enforce mode, expect 446 and the reason under hook_results:
The trace_id is the same identifier the finding carries in Activity, so use it to reconcile a request with what the console shows. If a blocking prompt returns 200, check that the hook sets deny: true and that the policy is in Enforce rather than Report. A 446 whose explanation reads TrustGuard authentication failed is the fail-closed path, not a policy decision — the key is wrong.

Streaming responses

The after-request hook receives no parsed body on a streamed response. The plugin returns a pass without calling TrustGuard rather than evaluating nothing and reporting a verdict it did not get.
With stream: true the response side is not inspected at all — not merely inspected too late. Input-side enforcement is unaffected and still happens before the model is called.
For coverage on the response, either disable streaming on the routes that need it, or put TrustGate in front — it is the only collector that buffers and inspects a stream.

Before the native plugin ships

Until a Portkey release carries neuraltrust.evaluate, the same connection is available as a Bring-Your-Own-Guardrails webhook, which needs no gateway build and works on Portkey Cloud.
  1. Create an API key on the collector.
  2. In Portkey, add a Guardrail Webhook check aimed at the evaluate URL.
  3. Attach it under before_request_hooks / after_request_hooks with deny: true.
  4. Map Portkey user and trace metadata to consumer_id and session_id.
The webhook contract is { verdict }, so the mapping is yours to make: derive verdict from TrustGuard status (status != "block") or Portkey will not enforce the decision. transform has nowhere to go on this path — a masking policy becomes allow or deny, so pair the webhook with policies that block rather than redact.

Limits to keep in mind

  • Only traffic through the gateway is inspected. Anything calling a provider directly bypasses TrustGuard, so the network path has to make the gateway the only way out.
  • The check runs on chat completions, text completions and Anthropic Messages. Embeddings and any request type the plugin does not recognise are treated as nothing to check and pass through.
  • Each guarded direction costs one round trip, so a turn with both hooks is two. Keep timeout tight enough that a stalled call cannot hold a request open.
  • The gateway sends session_id from request metadata but does not derive a consumer_id, so Activity groups by conversation rather than by virtual key.
Full contract for the endpoint behind all of this: Evaluate API.