Developer documentation
shim AI Gateway
Add tenant isolation, PII controls, quotas, spend limits, usage accounting, and audit evidence to native OpenAI, Anthropic, and Gemini API traffic.
Introduction
shim is an SDK-native governance gateway. It validates each request, resolves the authenticated tenant, applies privacy and admission policy, calls the selected provider, then settles usage and audit records. OpenAI and Anthropic clients can switch by changing the base URL and API key. Gemini clients keep their native routes. Compatibility is scoped to the documented endpoints, not every SDK resource.
Native provider APIs
OpenAI Responses and Chat, Anthropic Messages, and Gemini generateContent stay provider-native.
PII Scrubbing
Redact configured sensitive data before it reaches the selected provider, then restore it in the response.
Durable Governance
Enforce model, quota, and spend policy with tenant-scoped usage and audit records.
Authentication
Authenticate requests using your shim API Key. You can generate keys in Gateway keys.
Security Best Practice
Authorization: Bearer sk-shim-12345...x-shim-key: sk-shim-12345...Both methods are equivalent. The Anthropic SDK may instead send the shim key as x-api-key on its native Messages and Models routes. That header is gateway authentication, never Anthropic BYOK.
Quick Start
The Python examples use the official OpenAI and Anthropic SDKs. Gemini requests use its native endpoints and payloads. shim does not translate, route, or fail over requests between providers.
Set optional OpenAI and Gemini output limits so quota and spend reservation match the response size you intend. Omitting one reserves the platform ceiling, and Anthropic always requires max_tokens.
# Tested with openai==2.53.0
from openai import OpenAI
client = OpenAI(
base_url="https://api.getshim.tech/v1",
api_key="sk-shim-..."
)
response = client.responses.create(
model="gpt-5.6-luna",
input="Hello world",
max_output_tokens=128
)
chat = client.chat.completions.create(
model="gpt-5.6-luna",
messages=[{"role": "user", "content": "Hello world"}]
)
models = client.models.list()Coding agents
The gateway above covers the traffic your applications send. Your developers also run coding agents all day, and those calls never pass through it. shim-cli covers that side. It runs on the developer machine, with no account, API key or network call to shim, and it works with Claude Code, Codex, GitHub Copilot CLI and VS Code.
Install and connect
Install the CLI
uv tool install --python 3.12 --compile-bytecode shimUse pipx instead
pipx install --python python3.12 --fetch-missing-python shimWhen
python3 --versionalready says 3.10 or newer, this is enough:pipx install shimSee what it catches
shim demo claudeRuns the detector on a made-up sentence and shows it before and after masking. It installs nothing.
Connect it to Claude Code
Preview the change first, then install the hook.
shim install claude --dry-runshim install claude
Start a new session and check it
Start a new Claude Code session and run /hooks: shim is listed.
shim doctor claudeThen use Claude Code as you normally do. Masks secrets and personal data in the files and tool results your agent reads, before the model sees them.
Prefer a plugin?
Install from the Claude Code marketplace instead of running shim install. Use one method, not both.
/plugin marketplace add GetSHIM/shim-cli/plugin install shim-cli@shim-cli
Install the CLI
uv tool install --python 3.12 --compile-bytecode shimUse pipx instead
pipx install --python python3.12 --fetch-missing-python shimWhen
python3 --versionalready says 3.10 or newer, this is enough:pipx install shimSee what it catches
shim demo codexRuns the detector on a made-up sentence and shows it before and after masking. It installs nothing.
Connect it to Codex
Preview the change first, then install the hook.
shim install codex --dry-runshim install codex
Start a new session and check it
Start a new Codex session, open /hooks, review the shim entry and trust it. Codex skips a hook until you do.
shim doctor codexThen use Codex as you normally do. Reports what it found in your prompt and lets it through. Switch to enforce mode to block it instead.
Use shim install, not the Codex plugin
Current Codex installs the plugin and lists it as enabled, but does not load its hook: /hooks shows nothing, and prompts reach the model uninspected.
Install the CLI
uv tool install --python 3.12 --compile-bytecode shimUse pipx instead
pipx install --python python3.12 --fetch-missing-python shimWhen
python3 --versionalready says 3.10 or newer, this is enough:pipx install shimSee what it catches
shim demo copilotRuns the detector on a made-up sentence and shows it before and after masking. It installs nothing.
Connect it to Copilot CLI
Preview the change first, then install the hook.
shim install copilot --dry-runshim install copilot
Start a new session and check it
Start a new Copilot CLI session. It has no trust step.
shim doctor copilotThen use Copilot CLI as you normally do. Replaces the prompt the model receives with the redacted text, so the original values never reach it.
Get the plugin
Clone the release to a folder you keep. The
shimpackage does not carry the plugin.git clone --depth 1 --branch v1.2.1 https://github.com/GetSHIM/shim-cli ~/.local/share/shim-cliPoint VS Code at it
Add it to your user settings.json, with the absolute path that echo ~/.local/share/shim-cli/plugins/shim-cli prints. Workspace settings do not apply to this key.
"chat.pluginLocations": { "/Users/you/.local/share/shim-cli/plugins/shim-cli": true }There is no
shim install vscode. The plugin is the whole route. Then use VS Code as you normally do. In VS Code it reports, and with enforcement on it stops a prompt or denies a tool call before it runs. A result that has already reached the model is reported, never masked.
What each client does
By default a secret you type into a Claude Code or Codex prompt is reported, not stopped. To block it, put user-prompt = "enforce" under [mode] in ~/.config/shim/config.toml. If the file already has a [mode] header, add the line under it: a second header makes the whole file invalid.
[mode]user-prompt = "enforce"
Test it: a prompt holding ops@example.com must come back shim blocked this prompt: EMAIL (1).
See a session
shim watch runs Claude Code behind a local proxy for one command and reports the tokens, the spend and every sensitive value that went past. It changes nothing and writes no request body to disk.
shim watch -- claude
printf '%s' 'Mail alice@example.com' | shim redactNative Inference APIs
Each documented route preserves provider-owned request fields and native success JSON or SSE. Compatibility is endpoint-scoped rather than a promise that every SDK resource works, and shim never silently moves a request to another provider. OpenAI Responses background execution is excluded because shim does not expose its retrieval lifecycle.
POST /v1/responsesSupports native Responses input, tools, continuations, JSON, and SSE.
POST /v1/chat/completionsPreserves native OpenAI messages, tools, JSON, and SSE.
POST /v1/messagesSupports the Anthropic SDK's regular and beta Messages JSON and SSE semantics.
GET /v1/models[/{model_id}]Returns the native OpenAI or Anthropic catalog shape for the calling SDK.
POST /v1beta/models/{model}:generateContentUse :streamGenerateContent?alt=sse for native Gemini streaming.
Request Governance
On the request pathshim applies controls before an upstream call, then finalizes usage and audit state exactly once.
1. Authenticate
Resolve the tenant from the shim API key and load its policy.
2. Admit
Check the model catalog, RPM/TPM, quotas, loop protection, and spend policy.
3. Settle
Record actual tokens, cost, lifecycle status, and audit evidence.
Approved models only
400 MODEL_NOT_PRICED before the selected provider is called.Usage, Cost & Budgets
Durable recordsshim records daily requests, model usage, input/output tokens, and settled cost. Budgets can target an organization, team, or request tag with USD or token limits and alert thresholds.
Cost attribution
Assign an API-key cost center or send request tags for filterable activity and budget evaluation.
x-shim-tag: team:research,environment:prodBudget enforcement
Reserve estimated spend before the selected provider, settle actual usage afterward, and surface thresholds through the management API.
PII Protection
SecurityWhen enabled by tenant policy, shim scans prompts for PII (Personally Identifiable Information) at the gateway before sending them to the selected provider.
Original Prompt
"My email is alice@example.com"
Sent to AI
"My email is <EMAIL_ADDRESS_a6f1c49b2d807e35c84a917f0b6e2d43>"
Randomized placeholders are request-local and repeated values reuse the same placeholder within a request. The value is restored only in the client-facing response. OpenAI Responses continuations additionally use encrypted, tenant-bound, time-limited mappings. Other provider routes preserve their native conversation semantics. While scrubbing is enabled, opaque image, audio, and file inputs are rejected because shim cannot inspect them safely.
Detected PII Categories
| Category | Details |
|---|---|
| Financial | Luhn-validated credit cards and IBAN identifiers |
| Personal | Email Addresses, Phone Numbers, TCKN (Turkey ID), SSN |
| Secrets & Keys | AWS keys, OpenAI keys, GitHub tokens, and RSA, EC, OpenSSH, or encrypted private keys |
| Infrastructure | IP Addresses, MAC Addresses, Database Connection Strings |
Benchmarks
v0.4.2shim next to LiteLLM with its Presidio PII guardrail, on the same Turkish and English corpus, the same machine and the same mock provider. Every number can be re-run from the repository with one command.
| Measure | shim | LiteLLM + Presidio |
|---|---|---|
| Personal identifiers found | 88.8% | 80.0% |
| Precision of masking | 97.3% | 35.1% |
| Disguised identifiers that reach the provider | 0 of 940 | 49.4% |
| Secrets that reach the provider | 0 of 180 | 157 of 180 |
| Calls besides the provider, per request | none | 2–3 to the Presidio services |
| Latency with PII detection on, 1–50 KB prompts | 3.2–4.9× faster | baseline |
| To deploy | 1 container, 827 MB | 3 containers, 3.6 GB |
Measured gaps are published too: English person names are not detected yet (Turkish names are masked by default since v0.4.2), and a 32 KB prompt still takes more than shim's own 100 ms target in-process (107 ms on v0.4.1, about 10 ms more with Turkish names masked). Cost levers measured on real provider bills: Anthropic auto-cache saves 75.5% of input cost, tool search 75–77% on Claude.
Method, configurations and every table: BENCHMARKS.md · What changed in this release: v0.4.2 release notes
Rate Limits
Tenant policyshim applies configured request-per-minute and token-per-minute burst limits, durable daily/monthly quotas, and exact-repeat loop protection before the selected provider is called.
Burst controls
RPM and TPM are evaluated per authenticated API key.
Durable quotas
Request and token reservations prevent concurrent requests from overspending a period.
Loop protection
Repeated identical requests can be rejected before another billable call.
When a configured limit is exceeded, shim returns 429 Too Many Requests. Admission errors may also name the rejected dimension.
Streaming
shim preserves each provider's streaming response format: set stream: true for OpenAI or Anthropic, and call Gemini :streamGenerateContent?alt=sse.
Streaming remains governed
Audit & Compliance Evidence
shim keeps tenant-scoped request lifecycle and audit records and exposes audit-chain verification, evidence reports, findings, and oversight workflows through the management and compliance control planes.
Evidence
Review request status, model, usage, cost, privacy facts, audit chain, and generated reports without persisting raw prompt bodies in request records.
Oversight
Evaluate oversight policies, route flagged requests to a decision queue, and record human decisions when that control is enabled.
Compliance reports map observed evidence to controls. They are not legal advice, certification, or attestation.
Health Check
Use the health endpoint for monitoring and uptime checks.
GET https://api.getshim.tech/health{
"status": "ok",
"version": "0.1.0",
"database": "connected",
"redis": "connected"
}Dependency failures return a "degraded" status. A database failure also makes the health endpoint return HTTP 503. Redis health is reported separately.
Supported Models Reference
Chat Completions and Anthropic Messages require an approved model. OpenAI Responses may omit model and input to use the provider default, but an explicit model must be approved. GET /v1/models is provider-aware: the OpenAI and Anthropic SDKs receive native responses for their matching enabled catalogs. Gemini model admission remains on its native routes.
| Provider | Catalog | Admission |
|---|---|---|
| OpenAI | Use the OpenAI Models resource at /v1/models. | Unapproved models fail before the provider call. |
| Anthropic | Use the Anthropic Models resource at /v1/models. | Unapproved models fail before the provider call. |
| Configured Gemini models. Use the native Gemini Developer API routes. | Unapproved models fail before the provider call. |
Error Codes
| Code | Meaning | Solution |
|---|---|---|
| 400 MODEL_NOT_PRICED | Model Not Priced | Choose a model listed by the matching OpenAI or Anthropic SDK. |
| 400 INVALID_REQUEST | Invalid Request | Use a valid native output limit and candidate count. |
| 400 PRIVACY_POLICY_BLOCKED | Privacy Policy Blocked | Remove input that the enabled privacy policy cannot safely inspect or redact. |
| 401 | Unauthorized | Use a shim key through Authorization: Bearer, x-shim-key, or the Anthropic SDK's x-api-key. |
| 413 | Payload Too Large | The request exceeds the configurable body cap: 32,000,000 bytes by default (about 32 MB decimal). |
| 429 | Rate Limit Exceeded | A configured RPM, TPM, quota, or spend limit blocked the request. |
| 502 | Provider Request Failed | The selected provider rejected or could not complete the request. The response body is sanitized. |
| 503 | Service Unavailable | A required service or the selected provider is temporarily unavailable. Honor Retry-After when present. |
| 504 | Provider Timeout | The selected provider timed out. Retry only when your application's policy permits it. |
Provider failures preserve the upstream status and safe request ID but sanitize their bodies into the calling SDK's native envelope: OpenAI {"error": {...}} or Anthropic {"type": "error", "error": {...}, "request_id": "..."}.
Response Headers
Completed inference responses include the shim lifecycle identifier. Provider responses and sanitized provider errors include a safe upstream identifier when one is available.
Provider Credentials
Store an OpenAI, Anthropic, or Google key for the tenant in the dashboard, or supply one for a single request. shim consumes an invocation-scoped key as the provider credential and excludes it from durable request metadata. Authenticate shim separately with Authorization, x-shim-key, or the Anthropic SDK's gateway x-api-key. Only documented shim and provider-credential headers are interpreted. Arbitrary provider-specific caller headers are not forwarded upstream.
x-openai-api-key: sk-proj-...x-provider-key: sk-ant-...x-goog-api-key: AIza...x-provider-key is also a generic fallback for OpenAI and Google. The Anthropic SDK's x-api-key contains the shim key and authenticates the gateway, and it is never BYOK. Every invocation-scoped Anthropic provider key uses x-provider-key.
