Skip to main content
Developer Guide

Build Your Own Channel.

Every Arbitex channel is a lightweight adapter that calls one API endpoint. The Security API gives you the full 3-tier DLP pipeline, policy engine, and tamper-proof audit trail in a single HTTP call.

The Integration Surface

One endpoint. Full inspection.

Every channel module — AI Gateway, Email Relay, File Inspector, AppGuard, MCP Security — calls the same Security API. Your custom channel does too.

POSThttps://api.arbitex.ai/v1

Send content, get a decision. The platform engine runs DLP detection across all 3 tiers, evaluates policy rules, records a tamper-proof audit event, and returns allow, block, or redact with findings. Your channel handles the transport; the engine handles everything else.

Reference Implementation

MCP Security: minimal code, full channel.

MCP Security is the newest Arbitex channel — and the smallest. Here is how it works, section by section.

1

Authenticate

Validate the incoming JWT. Extract the tenant ID, user identity, and scopes. Every request is tied to a principal before any content is inspected.

# JWT validation — extract tenant + identity
token = request.headers.get("Authorization")
claims = verify_jwt(token, jwks_url=JWKS_ENDPOINT)
tenant_id = claims["tenant_id"]
user_id = claims["sub"]
2

Build Policy Context

Construct the context object the Security API needs: the channel name, the server or source identifier, and the direction (input or output).

# Policy context — tells the engine where this content came from
context = {
    "channel": "mcp",
    "server_id": request.json["server_id"],
    "tool_name": request.json["tool_name"],
    "direction": request.json.get("direction", "input"),
    "tenant_id": tenant_id,
    "user_id": user_id,
}
3

Call the Intake Pipeline

Send the content payload to the Security API. The engine runs all 3 DLP tiers, evaluates policy rules, and returns a decision — all in one call.

# One call — full DLP + policy + audit
result = security_api.evaluate(
    payload=request.json["payload"],
    context=context,
)
# result.decision: "allow" | "block" | "redact"
# result.findings: [{ "type": "PCI", "entity": "card_number", ... }]
4

Handle the Decision

Act on the engine's decision. Allow passes content through. Block returns an error to the caller. Redact strips sensitive entities and forwards the cleaned content.

# Enforce — your channel's only branching logic
if result.decision == "allow":
    return forward(request.json["payload"])
elif result.decision == "block":
    return error_response(403, result.findings)
elif result.decision == "redact":
    return forward(result.redacted_payload)
5

Audit Event Logged Automatically

You do not need to write audit code. The Security API records every evaluation — content hash, policy decision, findings, and tamper-proof audit trail link — automatically. Your channel gets full audit trail coverage for free.

Developer Portal

Self-service client registration.

Register your application as a named client identity. Every client gets its own API key, per-client policy, rate limits, and usage dashboard — without opening a support ticket.

Client Registration

Name your client, describe what it does, and select a transport type — API, MCP, or sidecar. The portal generates an API key and an SDK snippet scoped to that client. The platform ties every request to a named identity, not just an IP or tenant.

Sandbox Environment

New clients start in sandbox mode. Sandbox requests flow through the same DLP pipeline and policy engine but production enforcement is not applied — findings are recorded without blocking. Test your integration before it matters.

Production Promotion

Sandbox-to-production promotion requires admin approval by default. Admins can configure three self-service modes: Off (always requires approval), Approval Flow (60-day default sandbox lifespan, then approval), or Auto (admin-set lifespan, fully auditable). Every promotion is logged.

Per-Client Dashboard

Each registered client gets its own usage dashboard — request volume, DLP findings by policy, rate limit headroom, and webhook delivery status. Inline documentation is attached to the client record so the integration context never gets lost.

SDK Templates

Call the Security API from any language.

The integration is a single HTTP POST. Here are minimal working examples in six languages.

Python

import httpx
import os

API_KEY = os.environ["ARBITEX_API_KEY"]

def evaluate(text: str, server: str,
             direction: str = "input") -> dict:
    resp = httpx.post(
        "https://api.arbitex.ai/v1/mcp/evaluate",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "server_id": server,
            "tool_name": "custom",
            "payload": text,
            "direction": direction,
        },
    )
    return resp.json()
    # {"decision": "allow"|"block"|"redact",
    #  "findings": [...]}

JavaScript

const API_KEY = process.env.ARBITEX_API_KEY;

async function evaluate(text, server,
                        direction = "input") {
  const res = await fetch(
    "https://api.arbitex.ai/v1/mcp/evaluate",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        server_id: server,
        tool_name: "custom",
        payload: text,
        direction,
      }),
    }
  );
  return res.json();
}

Go

func evaluate(text, server,
              dir string) (Result, error) {
    body, _ := json.Marshal(map[string]string{
        "server_id": server,
        "tool_name": "custom",
        "payload":   text,
        "direction": dir,
    })
    req, _ := http.NewRequest("POST",
        "https://api.arbitex.ai/v1/mcp/evaluate",
        bytes.NewReader(body))
    req.Header.Set("Authorization",
        "Bearer "+os.Getenv("ARBITEX_API_KEY"))
    req.Header.Set("Content-Type",
        "application/json")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { return Result{}, err }
    defer resp.Body.Close()
    var result Result
    json.NewDecoder(resp.Body).Decode(&result)
    return result, nil
}

Java

HttpClient client = HttpClient.newHttpClient();

String evaluate(String text, String server,
                String direction) throws Exception {
    String json = String.format(
        "{\"server_id\":\"%s\","
        + "\"tool_name\":\"custom\","
        + "\"payload\":\"%s\","
        + "\"direction\":\"%s\"}",
        server, text, direction);
    HttpRequest req = HttpRequest.newBuilder()
        .uri(URI.create(
            "https://api.arbitex.ai/v1/mcp/evaluate"))
        .header("Authorization",
            "Bearer " + System.getenv("ARBITEX_API_KEY"))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers
            .ofString(json))
        .build();
    return client.send(req,
        HttpResponse.BodyHandlers.ofString())
        .body();
}

Rust

async fn evaluate(
    text: &str, server: &str, direction: &str,
) -> Result<Value, reqwest::Error> {
    let client = reqwest::Client::new();
    let resp = client
        .post("https://api.arbitex.ai/v1/mcp/evaluate")
        .bearer_auth(std::env::var("ARBITEX_API_KEY")
            .unwrap())
        .json(&serde_json::json!({
            "server_id": server,
            "tool_name": "custom",
            "payload": text,
            "direction": direction,
        }))
        .send()
        .await?;
    resp.json().await
}

C++

std::string evaluate(
    const std::string& text,
    const std::string& server,
    const std::string& direction) {
    httplib::Client cli(
        "https://api.arbitex.ai");
    httplib::Headers headers = {
        {"Authorization",
         "Bearer " + std::string(
             std::getenv("ARBITEX_API_KEY"))},
        {"Content-Type", "application/json"}
    };
    std::string body =
        R"({"server_id":")" + server +
        R"(","tool_name":"custom","payload":")" +
        text + R"(","direction":")" +
        direction + R"("})";
    auto res = cli.Post(
        "/v1/mcp/evaluate", headers,
        body, "application/json");
    return res->body;
}

Your content source. Our inspection engine.

See the channel size table on the Platform page to understand just how lightweight each adapter is.