status: "completed" and carries a refusal instead of generated text.
output_text is absent on a blocked response, so code that reads only output_text sees an empty answer and cannot tell a guardrail block apart from a model that said nothing.
If your org enforces guardrails, start with Detect a block in code.
How guardrails are applied
Two policies can apply to a request: the org-wide policy and the policy of the caller’s team. When both exist, both are enforced. A team policy adds rules on top of the org-wide policy; it never replaces or weakens it. If both policies match, the org-wide rule’s rejection message takes precedence. Policies apply to everyone in the scope; changingX-On-Behalf-Of does not create a separate policy for an end user.
Each guardrail always checks request input while it is enabled.
Checking model output is a separate opt-in per guardrail (see Check model output too).
The input check reads a string input or user-message text. It does not inspect image, audio, or file contents.
For the additional check before an auto-routing judge sees request evidence, see Auto routing.
API keys need the
read:guardrails scope to read or test guardrails and the write:guardrails scope to change them.
These scopes govern the policy endpoints; normal response requests are checked against the effective policy even if the key cannot manage guardrails.Guardrail modes
Every guardrail also takes two fields outside
config:
enabled(defaulttrue) turns the guardrail on or off without removing it from the policy.check_output(off unless set) additionally applies the guardrail to model output.
rejection_message.
Set your own to control exactly what a blocked caller reads back.
For example, banning secret also matches secrets; matching is not limited to whole words.
Prompt-injection and leakage checks use pattern detection, not a comparison against your actual system prompt.
Checks fail open: a policy lookup or evaluation error lets the request continue. A missing or empty policy also passes.
Configure guardrails
PUT /api/v1/llm/guardrails replaces a policy, so include every guardrail you want to keep.
Omit team_id or pass null to set the org-wide policy (organization admin or owner only).
Pass a team_id to set that team’s additional policy. With the required scope, team members can manage their own team’s policy; organization admins can manage any team in their organization.
Rules that team members must not be able to remove belong in the org-wide policy.
Before you start
Use an API key withread:guardrails, write:guardrails, and write:responses for the examples below, and a model available to your organization.
Use a dedicated test team, replace <team-id> with its ID, and make the test and response calls with a key belonging to that team.
Save the team’s existing row from GET /api/v1/llm/guardrails/policies before replacing it; the effective set from GET /guardrails also includes org-wide rules and is not a team-policy backup.
This example bans a word on both input and output, with a custom rejection message, and enables input leakage detection:
GET /api/v1/llm/guardrails or run mka1 guardrails get.
To see stored policies per scope, use GET /api/v1/llm/guardrails/policies.
Organization admins see all policies in their organization; other callers see the org-wide policy and their own team’s policy.
When you finish testing, restore the saved team policy with PUT, or delete the team’s policy with DELETE /api/v1/llm/guardrails?team_id=<team-id> if none existed before. Deleting a team policy leaves org-wide rules enforced.
Check model output too
Setcheck_output: true on a guardrail to also run it over the model’s generated text after the response is assembled.
This catches content the model produces on its own, such as a completion that repeats a banned term the user never typed.
It also covers Responses API output that would otherwise finish as incomplete, such as when a token limit is reached. A block replaces that result with a completed refusal and preserves the real usage.
Output checking is opt-in per guardrail, so enabling a guardrail never silently starts blocking completions your users already see.
It also bills differently: the model has already generated the tokens by the time the check runs, so a response blocked at the output stage still bills those tokens (see Usage and billing).
Test your policy
POST /api/v1/llm/guardrails/test evaluates a piece of content against your effective guardrails without calling a model.
Use it to validate a policy change before your traffic depends on it.
This endpoint uses the caller’s org and team; it has no team_id selector. It evaluates all enabled rules, not only those with check_output enabled.
details can explain why the guardrail fired: matched_word for ban_words, and a score or reason when provided by prompt_injection and leakage detection.
What a blocked response looks like
For a foreground Responses API request, a guardrail block returns HTTP 200 withstatus: "completed" and error: null.
For a background request, inspect the terminal response after polling or streaming; the initial response can still be queued or in_progress.
The block is visible in three places instead:
metadata.guardrail_triggeredholds the mode of the guardrail that fired (ban_words,prompt_injection, orleakage).outputcontains a single assistant message whose only content part hastype: "refusal", carrying the guardrail’s rejection message.usageis all zeros for an input block, because no model ran.
Detect a block in code
Read therefusal content part to show the caller a rejection message, and use metadata.guardrail_triggered to identify a platform guardrail block.
The SDK clients below use the same credentials as the configuration example. For the OpenAI SDK, initialize openai with your MKA1 API key and baseURL: 'https://apigw.mka1.com/api/v1/llm/', as shown in Generate a response.
output_text; use metadata.guardrail_triggered to label a platform guardrail block.
There is no top-level response.refusal field in the current MKA1 API.
Streaming
For a foreground input-stage block, the guardrail path emitsresponse.created and response.completed, each carrying the full blocked response object. Background streams can include earlier lifecycle events.
No response.output_text.delta events arrive, and there are no per-token refusal events.
A consumer that only listens for text deltas renders nothing, so handle the terminal event:
The following examples wait for the terminal response before displaying text, so output-stage blocks cannot expose a partial answer through this display code.
Applications that render deltas immediately must replace that partial answer if the terminal response contains a refusal.
check_output) behave differently under streaming.
The text deltas have already been sent by the time the output check runs, so they are not recalled.
The response.completed event and, when stored, the retrieved response carry the refusal in place of the generated text. Replace any displayed partial answer with that refusal; bytes already sent to the client cannot be recalled.
Usage and billing
- An input-stage block reports
usagewith every count at zero, and nothing is billed. The request never reached a model. - An output-stage block (
check_output) keeps the real token counts inusage, and those tokens are billed. The model generated the text before the check rejected it.
Chat Completions requests
The Chat Completions compatibility endpoint signals blocks in its own dialect. A blocked request returns HTTP 200 withfinish_reason: "content_filter" and the rejection message in message.refusal instead of message.content:
finish_reason: "content_filter" and the rejection message in delta.refusal after the text deltas.
Chat Completions cache hits are checked against the current output policy before replay. If cached text is blocked, it is withheld entirely, including for cached streams. Newly generated streams that trigger an output check are not cached.
Next steps
- Review the Guardrails endpoints in the API reference, including update, delete, and test
- See the authentication deep dive for giving each tenant its own guardrail policy
- See usage auditing for recording guardrail outcomes alongside the rest of your usage events
- See generate a response for the Responses API workflow guardrails sit in front of