Guardrails API
Manage guardrail rules as code and fetch live rule definitions — the public endpoints behind guardrails-as-code and SDK rule distribution.
Guardrails API
These endpoints let you author and manage guardrails programmatically ("guardrails as code") and expose the live rule definitions the SDK fetches at enforcement time. For the concept and the authoring UI, see Guardrails; for enforcement, see the SDK guardrails guide.
Authentication: all endpoints use project-key Basic Auth — pass your public key (pk-lf-...) as the username and secret key (sk-lf-...) as the password. The examples below read them from $AISDK_PUBLIC_KEY / $AISDK_SECRET_KEY.
Base URL: https://evals-api.browserstack.com
Guardrails must be enabled for the project — a gated feature you can turn on by contacting BrowserStack support. When guardrails are disabled, every endpoint returns 403 with { "error": "Guardrails are not enabled for this project." } — and the SDK treats that as a signal to skip the guardrail and let the call proceed.
The API can create and edit drafts but cannot promote a guardrail live. Promotion always goes through the validate-then-promote gate in the dashboard. Guardrails created or edited through the API stay in the draft state until promoted in the UI.
List guardrails
GET /api/public/v2/guardrailsReturns the latest version of every guardrail in the project (bounded to 200).
Response
{
"guardrails": [
{
"name": "pii-redact",
"version": 3,
"state": "live",
"hookPoint": "after_model",
"action": "redact",
"mechanism": "deterministic",
"ruleSpec": { "mode": "pii", "entities": ["email", "credit_card"] },
"judgePrompt": null,
"defaultResponseText": null
}
]
}cURL Example
curl https://evals-api.browserstack.com/api/public/v2/guardrails \
-u "$AISDK_PUBLIC_KEY:$AISDK_SECRET_KEY"Create a guardrail draft
POST /api/public/v2/guardrailsCreates a new guardrail in the draft state. Provide either a ruleSpec (deterministic) or a judgePrompt (LLM judge).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique guardrail name (1–200 chars). This is the SDK lookup key and cannot be changed later |
hookPoint | string | Yes | before_model, after_model, before_agent, after_agent, before_tool_call, after_tool_call |
action | string | Yes | default_response, redact, error_4xx, reask |
ruleSpec | object | Conditional | Deterministic rule (see below). Provide this or judgePrompt |
judgePrompt | string | Conditional | LLM-judge prompt. Provide this or ruleSpec |
defaultResponseText | string | No | Substitute text used when action is default_response |
provider | string | No | Advisory judge provider (LLM rules) |
model | string | No | Advisory judge model (LLM rules) |
The ruleSpec object is one of:
{ "mode": "keyword", "keywords": ["secret", "password"], "caseInsensitive": true }
{ "mode": "regex", "pattern": "\\d{3}-\\d{2}-\\d{4}", "caseInsensitive": false }
{ "mode": "pii", "entities": ["email", "credit_card", "ip_address", "mac_address", "url"] }
{ "mode": "json_schema", "schema": { "type": "object", "required": ["answer"] } }Response
{ "name": "block-secrets", "state": "draft" }Returns 409 with { "error": "A guardrail with this name already exists." } if the name is taken.
cURL Example
curl -X POST https://evals-api.browserstack.com/api/public/v2/guardrails \
-u "$AISDK_PUBLIC_KEY:$AISDK_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "block-secrets",
"hookPoint": "before_model",
"action": "error_4xx",
"ruleSpec": { "mode": "keyword", "keywords": ["api_key", "password"] }
}'Get a live guardrail (rule distribution)
GET /api/public/v2/guardrails/{guardrailName}Returns the live rule definition for a guardrail. This is the endpoint the SDK polls to keep its rule cache warm; it is cache-friendly.
Caching: the response carries an ETag header. Send it back as If-None-Match and the endpoint returns 304 Not Modified when the rule is unchanged. The SDK caches with a 60-second TTL and serves the last known rule if a refresh fails (stale-on-failure).
Response — live
{
"contractVersion": "1",
"name": "pii-redact",
"etag": "a1b2c3d4e5f6...",
"rule": {
"evaluatorId": "clx...",
"name": "pii-redact",
"hookPoint": "after_model",
"action": "redact",
"shortCircuit": true,
"timeoutMs": 2000,
"logic": {
"kind": "deterministic",
"spec": { "mode": "pii", "entities": ["email", "credit_card"] }
}
}
}Response — no live version
When no version of the guardrail is live, the endpoint returns 200 with an explicit unresolved status rather than a 404, so the SDK can skip the guardrail with a clear signal:
{
"contractVersion": "1",
"name": "pii-redact",
"etag": "...",
"reason": "no_live_version"
}cURL Example
curl https://evals-api.browserstack.com/api/public/v2/guardrails/pii-redact \
-u "$AISDK_PUBLIC_KEY:$AISDK_SECRET_KEY" \
-H 'If-None-Match: "a1b2c3d4e5f6..."'Update a guardrail (fork a new draft)
PUT /api/public/v2/guardrails/{guardrailName}Edits a guardrail by forking a new draft version. Any currently-live version is automatically demoted. The body takes the same fields as Create (except name, which is fixed).
Response
{ "name": "pii-redact", "state": "draft" }Returns 404 when the guardrail does not exist, and 409 with { "error": "Guardrail edit conflicted — please retry." } on a concurrent edit.
Archive a guardrail
DELETE /api/public/v2/guardrails/{guardrailName}Soft-deletes all versions of the guardrail (it stops being live and no longer appears in listings).
Response
{ "name": "pii-redact", "archived": true }Returns 404 when no matching guardrail is found.
cURL Example
curl -X DELETE https://evals-api.browserstack.com/api/public/v2/guardrails/pii-redact \
-u "$AISDK_PUBLIC_KEY:$AISDK_SECRET_KEY"Enforce LLM-judge rules
POST /api/public/guardrails/enforceEvaluates one or more LLM-judge guardrails against a piece of content and returns their decisions. This endpoint is called by the SDK for llm-logic rules (deterministic rules are enforced in-process and do not use it); you normally do not call it directly.
The judge runs server-side on your project's configured model credentials. All error, overload, and timeout responses are designed to let the caller skip the guardrail and let the call proceed.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
contractVersion | string | Yes | "1" |
guardrailNames | string[] | Yes | 1–50 live guardrail names to evaluate |
hookPoint | string | Yes | The hook point the content is being evaluated at |
content | string | Yes | The content to judge (max 200,000 chars) |
agentName | string | No | Canonical agent name |
traceId | string | No | Trace to attach the decision score to |
observationId | string | No | Observation to attach the decision score to |
environment | string | No | Trace environment (default "default") |
Response
{
"contractVersion": "1",
"decisions": [
{
"evaluatorId": "clx...",
"guardrailName": "jailbreak-judge",
"hookPoint": "before_model",
"action": "error_4xx",
"decision": "blocked",
"latencyMs": 412,
"model": "gpt-4o-mini",
"usage": { "input": 320, "output": 4, "total": 324 }
}
]
}Returns 413 when the payload exceeds the size limit and 503 ({ "error": "Guardrail enforcement is overloaded." }) when the judge concurrency cap is reached — in both cases the SDK skips the guardrail and the call proceeds.