Skip to content

Quickstart: 5-Minute Tutorial

This tutorial gets you from zero to a working Arbitex Gateway integration in five minutes. You will:

  1. Start the gateway with Docker Compose
  2. Configure a provider (your existing OpenAI or Anthropic API key)
  3. Send a request and see the gateway response
  4. Verify the request in the audit log
  5. Create your first DLP policy

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.


Clone the Arbitex Outpost repository and start the stack:

Terminal window
git clone https://github.com/arbitex/outpost.git
cd outpost
cp .env.example .env
docker compose up -d

Docker 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 Started

Confirm the gateway is ready:

Terminal window
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.


Add your AI provider credentials so the gateway can route requests on your behalf.

Terminal window
# Set your gateway admin credentials from .env
export ARBITEX_ADMIN_KEY="<arb_admin_...>"
# Add an Anthropic provider
curl -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.

Create a proxy API key that your applications will use to authenticate with the gateway:

Terminal window
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"
}
Terminal window
export ARBITEX_API_KEY="<arb_live_...>"

The gateway accepts requests in the standard OpenAI chat completions format. Use provider/model-id in the model field.

Terminal window
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_01HZ8X9K2P3QR4ST5UV6WX7YZ
X-Arbitex-Policy-Outcome: ALLOW
X-Arbitex-DLP-Findings: 0
X-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
import os
from 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.
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.

Every request is recorded in the tamper-evident audit log. Retrieve the most recent entry:

Terminal window
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

DLP policies define what happens when sensitive data is detected. Create a policy that blocks requests containing credit card numbers.

Terminal window
# Create a policy pack
curl -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"
}
Terminal window
PACK_ID="pack_01GHI789"
# Add a rule to the pack
curl -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 pack
curl -X POST "http://localhost:8301/api/v1/admin/policy-packs/$PACK_ID/activate" \
-H "Authorization: Bearer $ARBITEX_ADMIN_KEY"

Send a request that triggers the block:

Terminal window
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
}
]
}

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

Check Docker logs:

Terminal window
docker compose logs backend

Common causes:

  • Port 8300 or 8301 already in use — change PROXY_PORT / ADMIN_PORT in .env
  • Missing .env file — run cp .env.example .env first

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.

The configured provider returned an error. Check provider credentials under Settings → Providers and confirm your upstream API key has remaining quota.

A DLP policy blocked the request. Check the audit log entry for the dlp_findings array to see which entity type triggered the block.

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.