Quickstart: 5-Minute Tutorial
This tutorial gets you from zero to a working Arbitex Gateway integration in five minutes. You will:
- Start the gateway with Docker Compose
- Configure a provider (your existing OpenAI or Anthropic API key)
- Send a request and see the gateway response
- Verify the request in the audit log
- Create your first DLP policy
Prerequisites
Section titled “Prerequisites”Before you begin, make sure you have:
- Docker 24.x or later and Docker Compose v2 — verify with
docker compose version - API key for at least one AI provider — OpenAI, Anthropic, Google Gemini, Azure OpenAI, Groq, Mistral, Cohere, AWS Bedrock, or any OpenAI-compatible endpoint
- curl — for sending test requests from the terminal
No account creation required. The gateway runs entirely on your machine.
Step 1: Start the gateway
Section titled “Step 1: Start the gateway”Clone the Arbitex Outpost repository and start the stack:
git clone https://github.com/arbitex/outpost.gitcd outpostcp .env.example .envdocker compose up -dDocker Compose starts the following services:
| Service | Port | Description |
|---|---|---|
outpost |
8300 (AI proxy), 8301 admin API (localhost only) | AI proxy, DLP pipeline, policy engine, audit log |
Expected output:
[+] Running 1/1 ✔ Container outpost-outpost-1 StartedConfirm the gateway is ready:
curl http://localhost:8300/health{ "status": "ok", "version": "0.34.0", "dlp_tiers_active": ["regex", "ner"], "siem_status": "disabled", "cert_days_remaining": 87, "policy_bundle_age_seconds": 12.4, "credint_loaded": false, "geoip_anon_db_loaded": false, "geoip_city_loaded": false, "audit_logger_healthy": true, "budget_tracker_healthy": true}"status": "ok" confirms the gateway is running and ready. "dlp_tiers_active" lists which DLP scanning tiers are loaded. For readiness (policy bundle loaded and all critical subsystems up), use GET /ready instead.
Step 2: Configure your first provider
Section titled “Step 2: Configure your first provider”Add your AI provider credentials so the gateway can route requests on your behalf.
Using the API
Section titled “Using the API”# Set your gateway admin credentials from .envexport ARBITEX_ADMIN_KEY="<arb_admin_...>"
# Add an Anthropic providercurl -X POST http://localhost:8301/api/v1/admin/providers \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "anthropic-primary", "provider_type": "anthropic", "api_key": "sk-ant-your-anthropic-key", "is_default": true }'Expected response:
{ "id": "prov_01ABC123", "name": "anthropic-primary", "provider_type": "anthropic", "is_default": true, "status": "active", "created_at": "2026-03-13T00:00:00Z"}"status": "active" confirms the gateway validated your API key and the provider is ready.
Retrieve your gateway API key
Section titled “Retrieve your gateway API key”Create a proxy API key that your applications will use to authenticate with the gateway:
curl -X POST http://localhost:8301/api/v1/admin/api-keys \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "dev-testing", "role": "user"}'{ "id": "key_01DEF456", "name": "dev-testing", "key": "arb_live_xxxxxxxxxxxxxxxxxxxxxxxx", "role": "user", "created_at": "2026-03-13T00:00:00Z"}export ARBITEX_API_KEY="<arb_live_...>"Step 3: Send your first request
Section titled “Step 3: Send your first request”The gateway accepts requests in the standard OpenAI chat completions format. Use provider/model-id in the model field.
curl http://localhost:8300/v1/chat/completions \ -H "Authorization: Bearer $ARBITEX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "anthropic/claude-sonnet-4-20250514", "messages": [ { "role": "user", "content": "What is the capital of France? Answer in one sentence." } ], "max_tokens": 64 }'Expected response:
{ "id": "chatcmpl-arb_01HZ8X9K2P3QR4ST5UV6WX7YZ", "object": "chat.completion", "created": 1741820000, "model": "claude-sonnet-4-20250514", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The capital of France is Paris." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 20, "completion_tokens": 8, "total_tokens": 28 }}Note the response headers the gateway adds:
X-Arbitex-Request-Id: req_01HZ8X9K2P3QR4ST5UV6WX7YZX-Arbitex-Policy-Outcome: ALLOWX-Arbitex-DLP-Findings: 0X-Arbitex-Routing-Mode: Single| Header | Meaning |
|---|---|
X-Arbitex-Request-Id |
Unique ID — use this to look up the audit log entry |
X-Arbitex-Policy-Outcome |
Policy Engine decision: ALLOW, BLOCK, or REDACT |
X-Arbitex-DLP-Findings |
Number of sensitive data findings in the prompt/response |
X-Arbitex-Routing-Mode |
How the request was routed: Single, Fallback, or Balanced |
Python (OpenAI SDK)
Section titled “Python (OpenAI SDK)”import osfrom openai import OpenAI
client = OpenAI( base_url="http://localhost:8300/v1", api_key=os.environ["ARBITEX_API_KEY"],)
response = client.chat.completions.create( model="anthropic/claude-sonnet-4-20250514", messages=[ { "role": "user", "content": "What is the capital of France? Answer in one sentence.", } ], max_tokens=64,)
print(response.choices[0].message.content)# → The capital of France is Paris.Node.js
Section titled “Node.js”import OpenAI from "openai";
const client = new OpenAI({ baseURL: "http://localhost:8300/v1", apiKey: process.env.ARBITEX_API_KEY,});
const response = await client.chat.completions.create({ model: "anthropic/claude-sonnet-4-20250514", messages: [ { role: "user", content: "What is the capital of France? Answer in one sentence.", }, ], max_tokens: 64,});
console.log(response.choices[0].message.content);// → The capital of France is Paris.Step 4: Verify in the audit log
Section titled “Step 4: Verify in the audit log”Every request is recorded in the tamper-evident audit log. Retrieve the most recent entry:
curl "http://localhost:8301/api/v1/admin/audit-logs/?limit=1" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY"Expected response:
{ "items": [ { "id": "evt_01ABC...", "user_id": "usr_dev-testing", "action": "chat.completion", "model_id": "claude-sonnet-4-20250514", "provider": "anthropic", "outcome": "ALLOW", "dlp_findings": [], "credint_hit": false, "token_count_input": 20, "token_count_output": 8, "latency_ms": 843, "created_at": "2026-03-13T00:00:00.000Z", "src_ip": "172.18.0.1", "src_city": null, "src_country_code": null } ], "total": 1, "limit": 1, "offset": 0}Key fields:
| Field | What it tells you |
|---|---|
outcome |
Policy Engine decision — ALLOW, BLOCK, or REDACT |
dlp_findings |
Array of DLP detections — empty means no sensitive data found |
latency_ms |
End-to-end request time through the gateway |
credint_hit |
Whether the prompt matched the credential intelligence corpus |
Step 5: Create your first DLP policy
Section titled “Step 5: Create your first DLP policy”DLP policies define what happens when sensitive data is detected. Create a policy that blocks requests containing credit card numbers.
Using the API
Section titled “Using the API”# Create a policy packcurl -X POST http://localhost:8301/api/v1/admin/policy-packs \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "block-pii", "description": "Block requests containing credit card numbers" }'{ "id": "pack_01GHI789", "name": "block-pii", "status": "inactive"}PACK_ID="pack_01GHI789"
# Add a rule to the packcurl -X POST "http://localhost:8301/api/v1/admin/policy-packs/$PACK_ID/rules" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "block-credit-cards", "condition": { "type": "dlp_match", "entity_type": "CREDIT_CARD" }, "action": "BLOCK" }'
# Activate the packcurl -X POST "http://localhost:8301/api/v1/admin/policy-packs/$PACK_ID/activate" \ -H "Authorization: Bearer $ARBITEX_ADMIN_KEY"Test the policy
Section titled “Test the policy”Send a request that triggers the block:
curl http://localhost:8300/v1/chat/completions \ -H "Authorization: Bearer $ARBITEX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "anthropic/claude-sonnet-4-20250514", "messages": [ { "role": "user", "content": "My card number is 4532-1234-5678-9012. Can you confirm it is valid?" } ] }'Expected response (HTTP 400):
{ "error": { "message": "Request blocked by DLP policy: sensitive data detected in prompt", "type": "dlp_block", "code": "dlp_policy_violation", "request_id": "req_01JKL..." }}The request never reached the model. Verify in the audit log:
{ "outcome": "BLOCK", "dlp_findings": [ { "tier": "regex", "type": "CREDIT_CARD", "location": "prompt", "confidence": 1.0, "redacted": false } ]}What’s next
Section titled “What’s next”You now have a working gateway with DLP enforcement and a tamper-evident audit trail.
| Next step | Guide |
|---|---|
| Add fallback providers and configure routing | Routing and Failover |
| Configure redact mode instead of block | DLP Pipeline Configuration |
| Set up policy packs with approval workflows | Policy Engine Overview |
| Connect your SIEM for real-time event forwarding | SIEM Integration |
| Configure user quotas and budget enforcement | Quota Management |
| Review deployment options (SaaS, Hybrid, Air-Gap) | Deployment Topologies |
Troubleshooting
Section titled “Troubleshooting”Gateway does not start
Section titled “Gateway does not start”Check Docker logs:
docker compose logs backendCommon causes:
- Port 8300 or 8301 already in use — change
PROXY_PORT/ADMIN_PORTin.env - Missing
.envfile — runcp .env.example .envfirst
401 Unauthorized on proxy requests
Section titled “401 Unauthorized on proxy requests”Your API key is invalid or you are using the admin key instead of a proxy key. Proxy keys start with arb_live_. Retrieve one from Settings → API Keys.
503 Service Unavailable
Section titled “503 Service Unavailable”The configured provider returned an error. Check provider credentials under Settings → Providers and confirm your upstream API key has remaining quota.
400 Bad Request with dlp_policy_violation
Section titled “400 Bad Request with dlp_policy_violation”A DLP policy blocked the request. Check the audit log entry for the dlp_findings array to see which entity type triggered the block.
Wrong model ID format
Section titled “Wrong model ID format”Use the provider/model-id format: anthropic/claude-sonnet-4-20250514, openai/gpt-4o, google/gemini-2.0-flash. Run GET /v1/models to see all models available to your organization.