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.
Submit your crew's transaction chain and Arbiter traces backward from failure to assign fault scores per agent.
The fault engine resolves most disputes in under a second. No queue — resolution arrives with submission.
Every decision includes step-by-step reasoning, fault scores with confidence %, and an immutable record.
Same chain + same SLA policies = same outcome. No opinion, no bias. Reproducible for compliance.
CrewAI crews sub-delegate across agents. Arbiter handles chains of any depth: buyer → orchestrator → worker.
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.
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.
# Set as environment variable export ARBITER_API_KEY=arb_live_your_key_here
Register each agent in your CrewAI crew once at startup. Arbiter deduplicates by external_agent_id — safe to call on every boot.
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}}'
When a crew task fails, submit the full transaction chain. Include every agent involved — who delegated, who executed, where it broke down.
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.
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
npm install arbiter-client
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 Type | Severity | Common in CrewAI | Resolution |
|---|---|---|---|
| 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.