Documentation

Everything you need to add cost tracking, caching, security, and observability to your AI agents. Zero code changes to your LLM logic.

TL;DR: Point your OpenAI/Groq/Anthropic SDK to https://plumb.samji.in/v1 instead of the provider URL. Add an x-tenant-id header. Done.

Quick Start (2 minutes)

Step 1: Sign up

Go to /login and sign in with Google or GitHub. The Dev tier is free forever.

Step 2: Create an API key

Go to Dashboard → API Keys → Create Key. Copy the sk-... key.

⚠️ The key is shown only once. Store it securely.

Step 3: Send your first request

curl -X POST https://plumb.samji.in/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_LLM_PROVIDER_KEY" \
  -H "x-proxy-key: sk-YOUR-PROXY-KEY" \
  -H "x-upstream: groq" \
  -d '{
    "model": "llama-3.1-8b-instant",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

Step 4: Check your dashboard

Go to your dashboard — you'll see your request, token usage, cost, and cache status in real-time.


Authentication

There are two separate keys involved:

Your Proxy Key

Identifies you to our proxy. Sent as:

x-proxy-key: sk-your-proxy-key

Created in your dashboard. Tracks your usage and applies your rate limits.

Your LLM Provider Key

Your actual OpenAI/Groq/Anthropic key. Sent as:

Authorization: Bearer sk-your-openai-key

Passed through to the upstream provider. We never store it.

Important: The Authorization header is always passed through to the upstream LLM. We never read, log, or store your provider API key.

Alternative: Tenant ID (no proxy key needed)

For quick testing, you can skip the proxy key and just use a tenant identifier:

# Simple mode — just identify yourself
curl -X POST https://plumb.samji.in/v1/chat/completions \
  -H "Authorization: Bearer YOUR_LLM_KEY" \
  -H "x-tenant-id: my-company" \
  -H "x-upstream: groq" \
  -d '{"model":"llama-3.1-8b-instant","messages":[{"role":"user","content":"Hi"}]}'

Features

4-Layer Token Attribution

Every request is broken down into 4 cost layers:

  • Prompt tokens — your user messages
  • Tool tokens — function/tool definitions in the request
  • Memory tokens — system messages (RAG context, instructions)
  • Response tokens — model output (4x more expensive on most providers)

💡 Tip: Move large tool schemas to a shared system prompt to reduce per-request tool token costs.

Semantic Caching

Identical requests are served from cache instantly, saving LLM costs. Cache is per-tenant (no cross-tenant leaks).

  • • Cache TTL: 15 minutes (configurable)
  • • Cache key: blake3 hash of normalized request intent
  • • Cache hit response includes x-cache: HIT header

💡 Tip: Agents that retry the same question benefit massively. 30%+ cache hit rates are common on repetitive agent workloads.

PII Redaction

Sensitive data is automatically masked before reaching the LLM provider:

  • • SSNs (123-45-6789) → [PII_SSN_0001]
  • • Emails → [PII_EMAIL_0002]
  • • Credit cards → [PII_CC_0003]
  • • Phone numbers → [PII_PHONE_0004]

💡 Masking is reversible — authorized users can reveal original values via the vault API.

Budget Caps & Rate Limiting

Prevent runaway agents from destroying your budget:

  • Daily budget cap — set a $ limit per tenant per day. Requests are rejected (429) when exceeded.
  • RPM rate limit — sliding window per-tenant (Free: 30, Growth: 200, Enterprise: 1000)
  • Token quota — daily token limit as a safety net

💡 Tip: Set conservative budget caps initially. You can always increase them from the dashboard.

RiskChain Detection

Detects multi-step attack patterns that look benign individually:

  • • Read sensitive file → encode → POST to external URL = data exfiltration
  • • Shell deobfuscation (hex-encoded commands decoded before analysis)
  • • Session-aware tracking via x-session-id header

💡 Tip: Always send x-session-id for multi-turn agent conversations to enable RiskChain.

Circuit Breaker & Failover

If your primary provider goes down, requests auto-route to a backup:

  • • 3 consecutive 5xx errors → circuit opens for 30 seconds
  • • Automatic failover to next available provider
  • • After 30s, one test request is sent to check recovery
  • • On success → circuit closes, normal routing resumes

Context Window Protection

Requests that exceed a model's context window are blocked before reaching the provider:

  • • GPT-4o: 128,000 tokens
  • • Claude 3.5: 200,000 tokens
  • • Llama 3.1: 131,072 tokens

💡 Saves you from paying for requests that would fail anyway.

Agent Loop-Breaker

Detects when a session re-issues the same request intent repeatedly and stops it before it burns budget:

  • • Uses the same semantic intent fingerprint as the L1 cache (blake3 hash of messages + tools)
  • • If the same fingerprint appears more than LOOP_MAX_REPEATS times (default 5) within LOOP_WINDOW_SECS (default 30s), the request is rejected
  • • Returns 429 with code agent_loop_detected
  • • Tracked per x-session-id (so separate conversations don't interfere)

💡 Set LOOP_MAX_REPEATS=0 to disable. Tune LOOP_WINDOW_SECS higher for long-running agent sessions.

Prompt-Injection & Tool-Poisoning Defense

Scans both message content and tool definitions for adversarial patterns:

  • Instruction override — "ignore previous instructions", system prompt extraction attempts
  • Tool-description poisoning — hidden imperatives, sensitive-resource references, encoded blobs in MCP/OpenAI tool schemas
  • Unicode-tag smuggling — invisible characters (U+E0000–U+E007F) used to hide instructions
  • • High-confidence attacks → 403 prompt_injection_blocked
  • • Lower-confidence signals → flagged in the activity feed (no block)

💡 This protects you from untrusted MCP servers and malicious RAG content injecting instructions into your agent's context.

Declarative Policy Rules

A rule engine evaluates each request against configurable security policies:

  • Actions: block (reject 403), redact (mask matched content), alert (log + continue), log (silent record)
  • • Default rules catch credential exfiltration, SQL injection, and prompt-injection patterns
  • • Rules use precompiled regexes — zero allocation overhead on the hot path
  • • List active rules via GET /api/rules

💡 Blocked requests return 403 policy_blocked with the rule name in the response body.

Time-Travel Trace & Replay

Every request is traced end-to-end with a unique ID and can be replayed deterministically:

  • • Every response includes an x-trace-id header
  • • Traces record: governance steps, cache disposition, status, latency, token/cost outcome
  • GET /api/traces — list recent traces (admin-gated)
  • GET /api/traces/{id} — inspect a single trace
  • POST /api/traces/{id}/replay — replay the original request and diff the response (hash comparison)
  • • Traces persist to SQLite so they survive restarts

💡 Use replay to verify that a policy change doesn't break working requests (regression testing for governance).

Enterprise Memory Fabric

A tenant-isolated, multi-tier memory API for stateful agent workflows:

  • Working memory — ephemeral session KV (auto-expires, scoped to a run)
  • Episodic memory — append-only event log (audit trail, learning from past actions)
  • Semantic memory — versioned facts with event-sourcing (CAS conflicts → 409)
  • • Sensitivity labels + clearance-gated reads (confidential facts don't leak to lower clearance)
  • • Full version history on semantic facts (GET /api/memory/semantic/{key}/history)
  • • Deterministic keyword retrieval (no vector-search staleness)

💡 Use working memory for scratchpad, episodic for observability, semantic for distilled knowledge your agents share across sessions.

Cache-Aware Cost Accounting

Accurate spend tracking that accounts for provider prompt-cache discounts:

  • • Parses OpenAI cached_tokens in usage responses
  • • Parses Anthropic cache_read_input_tokens and cache_creation_input_tokens
  • • Prices each token class at its true rate (cache-read ≈ 10% of list price)
  • • Dashboard shows actual spend vs. naive spend (list-price × all tokens) and the savings delta

💡 This means your cost dashboards show real costs, not inflated estimates — critical for accurate FinOps.


Supported Providers

Set the x-upstream header to route to any provider:

x-upstreamProviderFree Tier?Best For
groqGroq✅ YesFastest inference, free Llama models
openrouterOpenRouter✅ Some modelsAccess to 100+ models via one key
togetherTogether AI✅ $5 creditOpen-source models, fine-tuning
(default)OpenAI❌ PaidGPT-4o, best overall quality
anthropicAnthropic❌ PaidClaude, 200k context window
localOllama✅ FreeLocal models, privacy

💡 Start with Groq (free, fast) for testing. Switch to OpenAI/Anthropic for production quality.


SDK Integration

Python (OpenAI SDK)

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_LLM_KEY",  # Your Groq/OpenAI key
    base_url="https://plumb.samji.in/v1",
    default_headers={
        "x-proxy-key": "sk-your-proxy-key",
        "x-upstream": "groq"  # or "openai", "anthropic", etc.
    }
)

response = client.chat.completions.create(
    model="llama-3.1-8b-instant",
    messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)

TypeScript / Node.js

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "YOUR_LLM_KEY",
  baseURL: "https://plumb.samji.in/v1",
  defaultHeaders: {
    "x-proxy-key": "sk-your-proxy-key",
    "x-upstream": "groq",
  },
});

const response = await client.chat.completions.create({
  model: "llama-3.1-8b-instant",
  messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);

LangChain (Python)

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="llama-3.1-8b-instant",
    openai_api_key="YOUR_GROQ_KEY",
    openai_api_base="https://plumb.samji.in/v1",
    default_headers={
        "x-proxy-key": "sk-your-proxy-key",
        "x-upstream": "groq"
    }
)

response = llm.invoke("What is 2+2?")
print(response.content)

curl

curl -X POST https://plumb.samji.in/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_LLM_KEY" \
  -H "x-proxy-key: sk-your-proxy-key" \
  -H "x-upstream: groq" \
  -d '{
    "model": "llama-3.1-8b-instant",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

API Reference

Proxy Endpoints

MethodPathDescription
ANY/v1/*Proxy to LLM provider (OpenAI-compatible)
ANY/anthropic/*Proxy to Anthropic API
ANY/mcp/*Proxy to MCP server (JSON-RPC 2.0)

Management Endpoints

MethodPathDescription
GET/healthHealth check (returns "ok")
GET/api/statsGlobal metrics (requests, cache, cost, tokens)
GET/api/stats/historyTime-series metrics (10s intervals)
GET/api/tenantsList all tenants and their usage
GET/api/tenants/{slug}/statsPer-tenant usage (daily spend, budget %)
GET/api/keysList API keys
POST/api/keysCreate API key
DELETE/api/keys/{id}Revoke an API key
GET/api/eventsSSE stream of real-time events
GET/api/rulesList active security policy rules
GET/api/vault/tokensList PII vault tokens (admin-gated)
GET/api/vault/reveal/{token}Reveal original PII value (admin/security role, tenant-scoped)
GET/api/vault/auditPII vault reveal audit log
GET/api/tracesList recent request traces (admin-gated)
GET/api/traces/{id}Inspect a single trace with governance steps
POST/api/traces/{id}/replayReplay a traced request and diff the response
GET/api/memory/working/{key}Read working memory entry
PUT/api/memory/working/{key}Write working memory entry
GET/api/memory/episodicQuery episodic event log
POST/api/memory/episodicAppend event to episodic memory
GET/api/memory/semantic/{key}Read semantic fact (clearance-gated)
PUT/api/memory/semantic/{key}Write/update semantic fact (CAS with expected_version)
GET/api/memory/semantic/{key}/historyVersion history of a semantic fact
GET/api/memory/semanticSearch semantic memory by keyword
POST/auth/tokenGet JWT token (testing only)

Request Headers

HeaderRequiredDescription
AuthorizationYour LLM provider key (passed through to upstream)
x-proxy-keyRecommendedYour proxy API key (identifies tenant via DB)
x-tenant-idAlternativeTenant slug (use if you don't have a proxy key)
x-upstreamOptionalOverride provider: groq, openrouter, anthropic, together, local
x-session-idOptionalSession ID for RiskChain multi-step tracking and loop detection
x-agent-idOptionalAgent identity for per-agent stats and anomaly detection

Response Headers

HeaderDescription
x-cacheHIT if served from cache (no LLM call made)
x-trace-idUnique trace identifier for this request (always present)
x-agent-safefixSafeFix suggestion — a safer alternative command when the request contains risky operations (present only when triggered)

FAQ & Tips

Does this add latency to my requests?

Minimal. The proxy adds ~30µs p50 / ~55µs p99 of governance overhead (measured via a deterministic micro-benchmark gating CI). Cache hits are served instantly (0ms to upstream). The latency you see is almost entirely from the LLM provider.

Can you see my LLM API key?

No. The Authorization header is passed through to the upstream provider without being logged or stored. We only read the x-proxy-key and x-tenant-id headers.

What happens if my budget cap is hit?

You'll get a 429 Too Many Requests response. Budget caps reset daily at midnight UTC. You can increase your cap from the dashboard or by upgrading your tier.

How does caching work? Will I get stale responses?

Cache is keyed on the semantic intent of your request (model + messages + tools). Cache TTL is 15 minutes. Different users/tenants never share cache. If you need fresh responses, slightly vary your prompt.

Can I use this with streaming responses?

Yes. SSE streaming (stream: true) is fully supported. Token tracking works for both streaming and non-streaming responses.

What if my provider goes down?

The circuit breaker detects 3 consecutive failures and automatically routes to a backup provider for 30 seconds. You'll see a "failover" event in your activity feed. Note: the backup provider must support the same model, or you'll need to handle model differences in your code.

Is my data stored?

We store: request metadata (model, token counts, cost, path, timestamp). We do NOT store: request/response bodies, your prompts, your LLM keys, or model outputs. PII is masked in-flight and never persisted.

How do I monitor my usage?

Three ways: (1) Dashboard at /dashboard, (2) API at plumb.samji.in/api/tenants/YOUR-SLUG/stats, (3) SSE event stream at plumb.samji.in/api/events for real-time monitoring.


💡 Pro Tips

Maximize cache hits

Use deterministic system prompts. Avoid timestamps or random IDs in messages. The more consistent your requests, the higher your cache hit rate.

Reduce tool token costs

Only include tools the agent actually needs for each request. Sending 20 tool definitions when only 2 are relevant wastes tokens on every call.

Use session IDs

Always send x-session-id for multi-turn conversations. This enables RiskChain to detect attack patterns across turns.

Start with Groq

Groq offers free Llama 3.1 inference with the fastest speeds. Perfect for development and testing before switching to paid providers.

Set budget caps early

A single agent loop can burn through hundreds of dollars in minutes. Set a conservative daily cap ($1-5 for dev, $50+ for production).

Monitor the activity feed

Keep curl -N plumb.samji.in/api/events running in a terminal during development to see every event in real-time.

Ready to get started?

Questions? Email support@samji.in