Guardrails

Every API key can carry its own protections: spend limits, model restrictions, an expiry date, and content scanning for prompt injection and sensitive data. All of them are optional, configured per key in your dashboard, and enforced before your request runs.

Why set guardrails

A single account often serves very different workloads — a production app, a teammate's experiment, a CI pipeline, a customer-facing chatbot. Guardrails let each key carry exactly the blast radius it deserves:

A leaked key can't drain your balance

A key with a daily spend limit and a model allowlist is worth very little to whoever finds it in a public repo.

A runaway script stops itself

An agent stuck in a loop hits its key's daily limit and stops — instead of burning through your credits overnight.

Untrusted input gets screened

If end users type into your product and that text reaches a model, content scanning catches prompt-injection attempts and accidental PII before they ever leave your key.

Spend & access limits

Four independent limits, each optional. When one is hit, the request is rejected with a specific error code before anything is billed.

Lifetime credit limit

A hard cap on the total a key may ever spend, in USD credits. Useful for one-off projects and trial integrations. Reaching it returns 429 credit_limit_exceeded.

Monthly & daily spend limits

Cap spend per calendar month or per day. The counters reset automatically. Returns 429 monthly_spend_limit_exceeded or 429 daily_spend_limit_exceeded.

Model allowlist

Restrict a key to specific models — for example, pin a production key to the exact model you tested against, or keep an experimentation key away from expensive models. A call to any other model returns 403 model_not_allowed.

Key expiry

Give a key an expiry date — for contractors, demos, or anything temporary. After it passes, the key returns 401 api_key_expired and can no longer be used.

Content scanning

Opt a key into scanning the user-supplied text of chat requests before it reaches any model. Two independent guardrails are available:

Prompt injection

Detects “ignore previous instructions”-class attacks, including common evasion techniques: base64- and hex-encoded payloads, scrambled spelling, spaced-out letters, and newline-split phrases. Scanning covers user and tool messages — your own system prompt is never second-guessed.

Sensitive info (PII)

Detects email addresses, phone numbers, SSNs, credit card numbers (Luhn-validated), and IPv4 addresses. You choose which of these patterns apply per key.

Three modes

Each guardrail is set to one of three modes, independently:

flag— observe only

The request runs untouched; the finding is recorded in your request logs. Start here to measure false positives on your real traffic before enforcing anything.

redact— sanitize and continue

Matched spans are replaced with a token before the request is forwarded — the model never sees the original text. Tokens: [PROMPT_INJECTION], [REDACTED_EMAIL], [REDACTED_PHONE], [REDACTED_SSN], [REDACTED_CARD], [REDACTED_IP].

block— reject the request

The request is rejected with 403 guardrail_blocked before any model runs — a blocked request never costs credits.

Blocked response
{
  "error": {
    "code": "guardrail_blocked",
    "message": "Request blocked by this API key's content guardrail (injection).",
    "type": "invalid_request_error"
  }
}

Knowing when a guardrail fired

When a guardrail fires in any mode, the response carries an x-apexapi-guardrails header listing which guardrail fired and in what mode, and the event appears in your request logs. Use flag mode plus this header to dry-run a policy against production traffic.

Privacy

Guardrail events never contain the matched text — we record only which kind of pattern fired and the action taken, never the offending content. That is separate from request-body storage: bodies are stored only if you enable body logging on the key, and under redact mode the stored body is the sanitized version.

Limitations

  • Detection is pattern-based and deliberately conservative — it raises the bar, it is not a guarantee. Treat it as one layer of defense, not the only one.
  • Scanning applies to chat completions only, and to the first 64KB of each text part.
  • False positives are possible (e.g. a phone-number pattern matching a dotted version string). Always start in flag mode.
  • Scanning is built to never break your traffic: if it cannot finish in time, the request proceeds unscanned rather than failing.

Recommended setups

Sensible starting points for common key types:

Customer-facing chatbot key

Daily spend limit sized to normal traffic, model allowlist pinned to your production model, prompt injection in block mode, sensitive info in redact mode. End users can't hijack your prompt or leak card numbers into model context.

Teammate or contractor key

Monthly spend limit, expiry date at the end of the engagement. Nothing to remember to revoke.

CI / automation key

Small lifetime or daily credit limit and a model allowlist with one cheap model. If the key leaks from a pipeline log, it's nearly worthless.

Compliance-sensitive workload

Sensitive info in redact mode with all patterns enabled — PII is stripped before it ever leaves your infrastructure, and the logs prove it without storing the data.

Setting up guardrails

Guardrails are configured per key in the dashboard — no code changes, and changes take effect immediately:

  1. Go to API Keys in your dashboard.
  2. Create a new key or edit an existing one.
  3. Use the tabs in the key dialog: Limits for spend caps, Models for the allowlist, and Scanning for content guardrails.
  4. Watch guardrail activity in your request logs and the x-apexapi-guardrails response header.

Spend limits are soft guardrails: they are checked before a request runs, so concurrent in-flight requests may briefly overshoot a limit before their usage is recorded. Your credit-balance ledger is the only hard stop — it can never be overspent.

Guardrail error codes

All guardrail rejections use a specific error code so your client can tell them apart from provider or billing errors. See Error Codes for the full list.

credit_limit_exceeded429

The key reached its lifetime credit limit.

monthly_spend_limit_exceeded429

The key reached its spend limit for the current calendar month.

daily_spend_limit_exceeded429

The key reached its spend limit for the current day.

model_not_allowed403

The requested model is not on this key's model allowlist.

api_key_expired401

The key's expiry date has passed.

guardrail_blocked403

Content scanning in block mode rejected the request before any model ran.