Integration Guide

Guardrails is a drop-in proxy. Your existing AI code doesn't change — you change one URL and one key, and every call is audited.

New to this? Not an engineer?

We wrote a plain-English setup guide that explains everything step by step — including a copy-paste prompt you can give to Claude, ChatGPT, or Copilot and let the AI make the change for you. If anything goes wrong, removing one line instantly puts your app back the way it was.

Download the Easy Setup Guide

Let your AI assistant install it

Using Claude, ChatGPT, Cursor, or Copilot? Paste this prompt and replace the two keys — the assistant finds the right file and makes the change:

Find where this project creates its AI client (OpenAI, Anthropic,
Gemini, or any OpenAI-compatible SDK).
- If it uses the OpenAI SDK (or an OpenAI-compatible one): set the
  base URL to https://aegisguardrails.com/v1, set the API key to
  <my Guardrails key>, and add a default header
  X-Provider-Key: <my existing AI provider key>.
- If it uses the Anthropic SDK: set the base URL to
  https://aegisguardrails.com/anthropic and add default headers
  X-Audit-Key: <my Guardrails key> and X-Provider-Key: <my Anthropic key>.
Don't change anything else.

1. Get your API key

Sign up at aegisguardrails.com/signup. Your GUARDRAILS_API_KEY will be shown in your dashboard.

2. Install the universal proxy (recommended)

One OpenAI-compatible endpoint serves every major model. Use the official OpenAI SDK — or anything that speaks the OpenAI chat-completions format — and switch models just by changing model. Claude requests are translated to Anthropic's API and back automatically, so every reply comes back in the same OpenAI shape.

Two changes: the base URL becomes https://aegisguardrails.com/v1, and the API key becomes your Guardrails key. Your provider key goes in an X-Provider-Key header — or save it once in the console under Settings → AI Provider Keys and leave the header out.

Node.js / TypeScript

import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'https://aegisguardrails.com/v1',
  apiKey: process.env.GUARDRAILS_API_KEY,          // your gr_ key
  defaultHeaders: {
    'X-Provider-Key': process.env.OPENAI_API_KEY,  // optional if saved in the console
    'X-Actor-Id': getCurrentUserId(),              // optional
  },
})

const reply = await client.chat.completions.create({
  model: 'gpt-4o-mini',      // or 'claude-sonnet-4-6', 'gemini-2.5-flash', 'grok-2', …
  messages: [{ role: 'user', content: 'Hello' }],
})

Python

from openai import OpenAI
import os

client = OpenAI(
    base_url="https://aegisguardrails.com/v1",
    api_key=os.environ["GUARDRAILS_API_KEY"],
    default_headers={"X-Provider-Key": os.environ["OPENAI_API_KEY"]},
)

reply = client.chat.completions.create(
    model="gemini-2.5-flash",
    messages=[{"role": "user", "content": "Hello"}],
)

curl

curl https://aegisguardrails.com/v1/chat/completions \
  -H "Authorization: Bearer $GUARDRAILS_API_KEY" \
  -H "X-Provider-Key: $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}'

Choosing a model

Guardrails works out the provider from the model name. Common prefixes are recognised automatically; for anything else, put the provider in front with a slash — e.g. deepseek/deepseek-chat or openai/my-fine-tune. GET /v1/models lists the common models.

ProviderRecognised automaticallyExplicit prefix
OpenAIgpt-*, o1 / o3 / o4…, chatgpt-*openai/
Anthropicclaude-*anthropic/ or claude/
Google Geminigemini-*gemini/ or google/
xAI Grokgrok-*grok/ or xai/
Meta Llamallama*, meta-llama*llama/ or meta/
DeepSeekdeepseek-*deepseek/
Alibaba Qwenqwen*qwen/ or alibaba/

The provider key you send must belong to the provider of the model you pick. To mix providers from one client, save each provider's key in the console and drop the X-Provider-Key header — Guardrails picks the right one per call.

3. Streaming

Set stream: true exactly as you would against the provider. Tokens are relayed the moment they arrive, and when the stream finishes Guardrails rebuilds the full reply and audits it like any other call — same hash, signature and on-chain anchor.

const stream = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  stream: true,
  messages: [{ role: 'user', content: 'Write a haiku' }],
})
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? '')
}
ModelsStreaming
OpenAI, Gemini, Grok, Llama, DeepSeek, QwenSupported — on /v1 and on their provider routes
Claude (Anthropic)Not yet — the reply arrives in one piece. Use stream: false for Claude models for now.
Azure OpenAI, AWS BedrockNot yet — the reply arrives in one piece.

4. Provider routes — keep your existing SDK

Already using a provider's own SDK? Point it at that provider's route instead and add two headers. Nothing else changes.

// Anthropic SDK
const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
  baseURL: 'https://aegisguardrails.com/anthropic',
  defaultHeaders: {
    'X-Audit-Key':    process.env.GUARDRAILS_API_KEY,
    'X-Provider-Key': process.env.ANTHROPIC_API_KEY,
    'X-Actor-Id':     getCurrentUserId(),     // optional
    'X-Session-Id':   getSessionId(),         // optional
  },
})

// OpenAI SDK, provider route (same idea for /grok, /gemini, /deepseek, /qwen, /llama)
const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: 'https://aegisguardrails.com/openai',
  defaultHeaders: {
    'X-Audit-Key':    process.env.GUARDRAILS_API_KEY,
    'X-Provider-Key': process.env.OPENAI_API_KEY,
  },
})
Base URLProviderExtra headers
/anthropicAnthropic (Messages API)—
/openaiOpenAI—
/geminiGoogle Gemini (OpenAI-compatible)—
/grokxAI Grok—
/llamaMeta Llama API—
/deepseekDeepSeek—
/qwenAlibaba Qwen (Model Studio)—
/azureAzure OpenAIX-Azure-Resource, X-Azure-Deployment, X-Azure-API-Version (optional)
/awsAWS BedrockX-AWS-Access-Key-Id, X-AWS-Secret-Access-Key, X-AWS-Region; model in the body or X-AWS-Model-Id

5. SDKs & tools

There's no Guardrails SDK to install — you keep the client you already use. What works today:

Not supported yet: the OpenAI Responses and Embeddings APIs, Gemini's native SDK (use Gemini through /v1 or /gemini instead), and streaming for Claude, Azure and Bedrock.

6. Read the audit metadata

Every non-streamed response includes an _audit field:

const reply = await client.chat.completions.create({ ... })
console.log(reply._audit)
// {
//   event_id: 'a3f8b21c-...',
//   hash: '3a7bd3e2...',
//   ledger_status: 'pending'  // → 'committed' after ~30s
// }

On a streamed response the same object arrives as an SSE comment line just before data: [DONE]. SDKs skip comment lines, so nothing breaks; if you read the raw stream yourself, look for the line that starts with : _audit:

data: {"id":"chatcmpl-…","choices":[{"delta":{"content":"lo"}, …}]}

: _audit {"event_id":"a3f8b21c-…","hash":"3a7bd3e2…","ledger_status":"pending"}

data: [DONE]

Fail-open guarantee

Guardrails sits in the path of every AI call you make, so the first question worth asking is: what happens if Guardrails itself has a problem? The answer is fail open — your AI call is never blocked by an audit-layer failure.

Internally, each call has two stages: forwarding the request to your AI provider, then fingerprinting, signing, and storing the audit record. Those stages fail differently, and we handle them differently:

When the audit pipeline is the part that failed, the _audit field tells you so instead of silently going missing:

// Audit pipeline failure — your AI response is still returned in full
{
  ...,             // your normal AI response, unaffected
  "_audit": {
    "event_id": null,
    "hash": null,
    "ledger_status": "audit_failed",
    "warning": "Guardrails could not record this call due to an internal error.
                 Your AI response was still returned. This call is not covered
                 by your audit trail."
  }
}

We recommend checking _audit.ledger_status for "audit_failed"if you want to alert on gaps in your audit coverage — but you never need to handle it defensively the way you'd handle a real API error, because your application keeps working either way.

There is one failure mode this can't cover: if our service is fully unreachable (network partition, DNS issue), no request reaches us at all. For that case, the same one-line design that makes installation easy also makes a fallback easy — point your client at the provider directly on catch:

// Optional client-side fallback if Guardrails is unreachable
let response
try {
  response = await guardrailsClient.messages.create({ ... })
} catch (err) {
  if (isConnectionError(err)) {
    response = await directAnthropicClient.messages.create({ ... }) // unaudited fallback
  } else {
    throw err
  }
}

7. Verify a record

Any record can be publicly verified — no login required:

GET https://aegisguardrails.com/verify/{event_id}

// Response
{
  "eventId": "a3f8b21c-...",
  "hash": "3a7bd3e2...",
  "platformSigValid": true,
  "customerSigValid": true,
  "onChain": true,
  "blockHeight": 41823,
  "tampered": false
}

8. Signing key — bring your own key (BYOK)

Every record is already signed by our platform key. For a second, independent signature that neither side can forge alone, generate a signing key pair in your console under Settings → Signing Key. The private key is generated in your browser, downloaded straight to your machine, and never sent to us — only the public key is registered with your account.

After a proxied call, you already have _audit.hash. Sign that hash with your private key (P-256 / ECDSA, SHA-256, IEEE-P1363 signature encoding) and submit it back — this is meant to run in your own backend, not the browser:

import { createSign, createPrivateKey } from 'crypto'

// privateKeyJwk is the JSON file downloaded when you generated your signing key
const key = createPrivateKey({ key: privateKeyJwk, format: 'jwk' })

const sign = createSign('SHA256')
sign.update(Buffer.from(response._audit.hash, 'hex'))
sign.end()
const signature = sign.sign({ key, dsaEncoding: 'ieee-p1363' }).toString('hex')

await fetch(`https://aegisguardrails.com/events/${response._audit.event_id}/cosign`, {
  method: 'POST',
  headers: { 'X-Audit-Key': process.env.GUARDRAILS_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({ signature }),
})

Once submitted, GET /verify/{event_id} reports customerSigValid: true alongside the platform signature — a regulator can confirm both independently, without ever needing your private key.

9. Aegis Verify — anchor any hash, no AI call required

Everything above audits AI calls specifically. If you just need to anchor a hash you've already computed — a contract revision, a decision log entry, an export of records — POST /anchorseals it on the same Verilink'ed ledger, Merkle-batched and publicly verifiable exactly like an AI call:

POST https://aegisguardrails.com/anchor
X-Audit-Key: <your Guardrails key>
Content-Type: application/json

{ "hash": "3a7bd3e2...", "label": "contract-v4-signed" }

// Response
{ "event_id": "a3f8b21c-...", "hash": "3a7bd3e2...", "ledger_status": "pending" }

The same GET /verify/{event_id} endpoint verifies it. This is the basis of Aegis Verify — useful anywhere you need a tamper-proof timestamp on something, independent of any AI provider.

10. Alerts — webhook / Slack

Set a webhook URL in the console under Settings → Alerts to get notified when usage crosses 50/80/100% of your plan, or when a call's audit record couldn't be saved. Any Slack incoming-webhook URL works directly — the payload includes a top-level text field, which is all Slack reads:

{
  "text": "Guardrails: you've used 80% of your plan's monthly call limit (40,000/50,000).",
  "event": "usage_threshold",
  "pct": 80
}

Headers reference

HeaderRequiredDescription
X-Audit-KeyYes*Your Guardrails API key. *On /v1, Authorization: Bearer <Guardrails key> works instead — that is what the OpenAI SDK sends.
X-Provider-KeyUnless savedYour AI provider's API key, forwarded to the provider. Optional if you've saved that provider's key in the console.
X-Actor-IdNoUser or service account ID — appears in the audit log
X-Session-IdNoGroups a multi-turn conversation together
X-AI-System-IdNoWhich registered AI system this call belongs to — turns on its Policy Engine rules

Azure and Bedrock take a few extra headers — see Provider routes.