🤝 Integration Guide

Arbiter + CrewAI

CrewAI agents transact on your behalf. When they fail — wrong output, partial delivery, unauthorized action — you need a resolution path that does not require human intervention. Arbiter is that path: deterministic dispute resolution for multi-agent pipelines, wired in with three API calls.

Why Arbiter + CrewAI

CrewAI handles task routing, delegation, and execution. Arbiter handles what happens when execution goes wrong. Together they close the loop on autonomous commerce — agents transact at speed knowing disputes are handled without human escalation.

🔍
Automatic Fault Detection

Submit your crew's transaction chain and Arbiter traces backward from failure to assign fault scores per agent.

Sub-second Resolution

The fault engine resolves most disputes in under a second. No queue — resolution arrives with submission.

📋
Full Audit Trail

Every decision includes step-by-step reasoning, fault scores with confidence %, and an immutable record.

⚖️
Deterministic

Same chain + same SLA policies = same outcome. No opinion, no bias. Reproducible for compliance.

🔗
Multi-hop Chains

CrewAI crews sub-delegate across agents. Arbiter handles chains of any depth: buyer → orchestrator → worker.

🛡️
SLA-backed

Register each agent with its SLA policy. Arbiter scores against declared expectations, not assumptions.

Quick Start

Three steps to connect a CrewAI crew to Arbiter dispute resolution.

1
Get your API key

Create an account at arbiter-2.polsia.app/docs and generate an API key. Production keys use the arb_live_ prefix. Test keys use arb_test_ for safe integration testing.

bash
# Set as environment variable
export ARBITER_API_KEY=arb_live_your_key_here
2
Register your agents

Register each agent in your CrewAI crew once at startup. Arbiter deduplicates by external_agent_id — safe to call on every boot.

curl
curl -X POST https://arbiter-2.polsia.app/api/agents   -H "Authorization: Bearer $ARBITER_API_KEY"   -H "Content-Type: application/json"   -d '{"external_agent_id":"crewai-researcher-001","name":"Research Agent","platform":"crewai","sla_policy":{"refund_window_hours":24,"max_retry_attempts":3}}'
3
Submit a dispute when a task fails

When a crew task fails, submit the full transaction chain. Include every agent involved — who delegated, who executed, where it broke down.

curl
curl -X POST https://arbiter-2.polsia.app/api/disputes   -H "Authorization: Bearer $ARBITER_API_KEY"   -H "Content-Type: application/json"   -d '{"description":"Researcher delivered empty dataset","chain_data":[{"agent_id":"crewai-orchestrator","action":"delegated_task","timestamp":"2026-04-28T10:00:00Z","amount":5.00},{"agent_id":"crewai-researcher-001","action":"delivered_dataset","timestamp":"2026-04-28T10:00:45Z","outcome":"failed","error":"empty_response"}]}'

# Then poll for resolution (arrives in <1s typically):
curl https://arbiter-2.polsia.app/api/disputes/1/resolution   -H "Authorization: Bearer $ARBITER_API_KEY"

Python Example

Full integration using the requests library. Drop this into your CrewAI task callbacks.

No Python SDK required — Arbiter's REST API works with any HTTP client. pip install requests is all you need.

python
import os, time, requests
from typing import Optional

ARBITER_BASE = "https://arbiter-2.polsia.app"
HEADERS = {
    "Authorization": "Bearer " + os.environ["ARBITER_API_KEY"],
    "Content-Type": "application/json",
}

def register_crew_agent(agent_id: str, name: str, sla: dict) -> Optional[int]:
    """Register a CrewAI agent. 409 = already registered, safe to ignore."""
    r = requests.post(ARBITER_BASE + "/api/agents", headers=HEADERS, json={
        "external_agent_id": agent_id, "name": name,
        "platform": "crewai", "sla_policy": sla,
    })
    if r.status_code not in (200, 201, 409):
        r.raise_for_status()
    return r.json().get("id")

def submit_dispute(description: str, chain: list) -> dict:
    r = requests.post(ARBITER_BASE + "/api/disputes", headers=HEADERS,
        json={"description": description, "chain_data": chain})
    r.raise_for_status()
    return r.json()

def await_resolution(dispute_id: int, timeout: int = 10) -> Optional[dict]:
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(
            ARBITER_BASE + "/api/disputes/" + str(dispute_id) + "/resolution",
            headers=HEADERS)
        if r.status_code == 200:
            return r.json()
        if r.status_code != 404:
            r.raise_for_status()
        time.sleep(0.5)
    return None


# ── Wire into CrewAI task callbacks ─────────────────────────────────

# 1. Register at startup (idempotent)
register_crew_agent("crewai-researcher-001", "Research Agent",
    sla={"refund_window_hours": 24, "max_retry_attempts": 3})
register_crew_agent("crewai-writer-002", "Writer Agent",
    sla={"refund_window_hours": 12, "quality_threshold": 0.9})

# 2. On task failure, submit the chain
dispute = submit_dispute(
    description="Writer produced output that failed validation",
    chain=[
        {"agent_id": "crewai-researcher-001", "action": "delivered_research_summary",
         "timestamp": "2026-04-28T10:00:00Z", "outcome": "success"},
        {"agent_id": "crewai-writer-002", "action": "generated_report",
         "timestamp": "2026-04-28T10:00:30Z", "outcome": "failed",
         "error": "missing_required_sections", "amount": 12.50},
    ])

# 3. Await resolution (typically <1s)
resolution = await_resolution(dispute["dispute_id"])
if resolution:
    r0 = resolution["resolutions"][0]
    print("Action:", r0["action"])       # e.g. "full_refund"
    print("Reasoning:", r0["reasoning"])
else:
    print("Timed out — dispute queued for manual review")

TypeScript Example

Full integration using the Arbiter TypeScript SDK. Typed request/response objects, no manual HTTP wiring required.

SDK is in open beta. Install: npm install arbiter-client

bash
npm install arbiter-client
typescript
import { ArbiterClient } from 'arbiter-client';

const arbiter = new ArbiterClient({
  apiKey: process.env.ARBITER_API_KEY!,
  baseUrl: 'https://arbiter-2.polsia.app',
});

// Register agents once at startup (idempotent)
async function ensureAgentsRegistered() {
  const agents = [
    { external_agent_id: 'crewai-researcher-001', name: 'Research Agent',
      platform: 'crewai', sla_policy: { refund_window_hours: 24 } },
    { external_agent_id: 'crewai-writer-002', name: 'Writer Agent',
      platform: 'crewai', sla_policy: { quality_threshold: 0.9 } },
  ];
  for (const agent of agents) {
    try { await arbiter.registerAgent(agent); }
    catch (err: any) { if (err?.status !== 409) throw err; }
  }
}

// Submit dispute and await resolution
async function handleCrewTaskFailure(description: string, chain: any[]) {
  const dispute = await arbiter.submitDispute(chain, { description });

  let resolution = null;
  for (let i = 0; i < 20; i++) {
    try {
      resolution = await arbiter.getResolution(dispute.dispute_id);
      break;
    } catch (err: any) {
      if (err?.status !== 404) throw err;
      await new Promise(r => setTimeout(r, 500));
    }
  }
  if (!resolution) { console.warn('Resolution timed out'); return null; }

  const { action, reasoning, fault_agent_id } = resolution.resolutions[0];
  console.log('Resolution:', action, '| Fault:', fault_agent_id);
  console.log('Reasoning:', reasoning);
  return resolution;
}

// Run
await ensureAgentsRegistered();
await handleCrewTaskFailure('Writer produced output that failed validation', [
  { agent_id: 'crewai-researcher-001', action: 'delivered_research_summary',
    timestamp: '2026-04-28T10:00:00Z', outcome: 'success' },
  { agent_id: 'crewai-writer-002', action: 'generated_report',
    timestamp: '2026-04-28T10:00:30Z', outcome: 'failed',
    error: 'missing_required_sections', amount: 12.50 },
]);

Fault Types Reference

Arbiter classifies every dispute into one of five fault categories. Understanding them helps you write better SLA policies and interpret resolution outcomes. Full definitions at /fault-taxonomy.

Fault TypeSeverityCommon in CrewAIResolution
Unauthorized Action
Exceeded scope or permissions
CRITICAL Tool use outside capability set; accessing data outside task scope Full refund + agent flagged
Incorrect Execution
Did wrong thing within scope
HIGH Wrong output format; logic errors; missing fields; quality miss Proportional credit
Partial Delivery
Some but not all work completed
HIGH Task abandoned mid-stream; token budget exhausted; scope shortfall Proportional credit + grace period
Misrepresentation
SLA claims didn't match reality
MEDIUM Accuracy claims vs. actual output quality; capability unavailable Restitution + SLA update
Third-Party Failure
External or upstream agent failed
LOW (no-fault) Upstream crew agent didn't deliver; external API outage Full refund, upstream liable

You don't pre-classify the fault type — Arbiter's engine determines it from the chain. See /fault-taxonomy for detection mechanisms, scoring rubrics, and resolution paths per category.

Next Steps

Grab your API key from the API docs, register your agents, and start submitting disputes. The full REST reference covers every endpoint, field, and error code.

Want to see how a specific CrewAI failure maps to fault taxonomy? Submit a test dispute on the dashboard and inspect the resolution reasoning — it shows exactly how Arbiter scored the chain.