BrowserStack AI Evals

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/guardrails

Returns 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/guardrails

Creates a new guardrail in the draft state. Provide either a ruleSpec (deterministic) or a judgePrompt (LLM judge).

Request Body

FieldTypeRequiredDescription
namestringYesUnique guardrail name (1–200 chars). This is the SDK lookup key and cannot be changed later
hookPointstringYesbefore_model, after_model, before_agent, after_agent, before_tool_call, after_tool_call
actionstringYesdefault_response, redact, error_4xx, reask
ruleSpecobjectConditionalDeterministic rule (see below). Provide this or judgePrompt
judgePromptstringConditionalLLM-judge prompt. Provide this or ruleSpec
defaultResponseTextstringNoSubstitute text used when action is default_response
providerstringNoAdvisory judge provider (LLM rules)
modelstringNoAdvisory 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/enforce

Evaluates 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

FieldTypeRequiredDescription
contractVersionstringYes"1"
guardrailNamesstring[]Yes1–50 live guardrail names to evaluate
hookPointstringYesThe hook point the content is being evaluated at
contentstringYesThe content to judge (max 200,000 chars)
agentNamestringNoCanonical agent name
traceIdstringNoTrace to attach the decision score to
observationIdstringNoObservation to attach the decision score to
environmentstringNoTrace 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.

See also