API Reference
Arbiter provides a REST API for submitting disputes, registering agents, and retrieving resolutions in multi-agent transaction chains. All requests and responses use JSON.
Base URL
https://arbiter-2.polsia.app
All endpoints are relative to this base URL. TLS is required — HTTP requests are not accepted.
Authentication
Arbiter uses API key authentication. Pass your API key as a Bearer token in the Authorization header on every request.
Authorization: Bearer arb_live_your_api_key_here
The API is currently in open beta. Authentication is enforced for production traffic. Keep your API key secret — treat it like a password. Never commit it to source control.
API Key Prefixes
| Prefix | Environment | Description |
|---|---|---|
| arb_live_ | production | Live disputes — real resolution logic applied |
| arb_test_ | sandbox | Test disputes — no real settlement, safe for integration testing |
Quick Start
Submit your first dispute in 3 API calls.
Before submitting a dispute, register each agent involved in the transaction chain.
curl -X POST https://arbiter-2.polsia.app/api/agents \ -H "Authorization: Bearer arb_live_..." \ -H "Content-Type: application/json" \ -d '{ "external_agent_id": "agent-buyer-001", "name": "BuyerBot", "platform": "sapiom", "sla_policy": { "refund_window_hours": 24 } }'
Include every hop in the chain — who initiated, who was subcontracted, and where delivery broke.
curl -X POST https://arbiter-2.polsia.app/api/disputes \ -H "Authorization: Bearer arb_live_..." \ -H "Content-Type: application/json" \ -d '{ "description": "Agent C delivered corrupt data payload", "chain_data": [ { "agent_id": "agent-buyer-001", "action": "initiated_purchase", "timestamp": "2026-04-23T10:00:00Z", "amount": 150.00 }, { "agent_id": "agent-fulfiller-002", "action": "accepted_subcontract", "timestamp": "2026-04-23T10:00:05Z" }, { "agent_id": "agent-data-003", "action": "delivered_output", "timestamp": "2026-04-23T10:01:30Z", "outcome": "failed", "error": "null_payload" } ] }'
Poll the resolution endpoint until the dispute status is resolved. Resolution typically completes within seconds.
curl https://arbiter-2.polsia.app/api/disputes/1/resolution \ -H "Authorization: Bearer arb_live_..."
Agents
Register an agent with an optional SLA policy. Once registered, an agent can be referenced in dispute submissions. Agents are deduplicated by external_agent_id.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| external_agent_id | string | required | Your unique identifier for this agent. Max 255 chars. |
| name | string | required | Human-readable name. Max 255 chars. |
| platform | string | required | Platform this agent operates on (e.g. sapiom, stripe-acp, coinbase-x402). Max 255 chars. |
| sla_policy | object | optional | SLA terms applied during fault determination. Free-form JSON object. E.g. { "refund_window_hours": 24, "max_retry_attempts": 3 }. |
Response
{
"id": 42,
"external_agent_id": "agent-buyer-001",
"name": "BuyerBot",
"platform": "sapiom",
"sla_policy": { "refund_window_hours": 24 },
"created_at": "2026-04-23T10:00:00.000Z"
}
Status Codes
201 Created 400 Validation error 409 Duplicate external_agent_id 500 Server errorReturns all registered agents, sorted by registration date descending. Optionally filter by platform.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| platform | string | optional | Filter by platform name. Exact match. |
Example
curl "https://arbiter-2.polsia.app/api/agents?platform=sapiom" \ -H "Authorization: Bearer arb_live_..."
Response
{
"agents": [
{
"id": 42,
"external_agent_id": "agent-buyer-001",
"name": "BuyerBot",
"platform": "sapiom",
"sla_policy": { "refund_window_hours": 24 },
"created_at": "2026-04-23T10:00:00.000Z"
}
],
"count": 1
}
Status Codes
200 OK 500 Server errorDisputes
Submit a dispute with the full transaction chain. Arbiter traces the chain to determine fault and enqueues the dispute for resolution. The dispute starts with status open.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| chain_data | array | required | Ordered array of transaction hops. Each hop requires agent_id, action, and timestamp. |
| description | string | optional | Human-readable description of the dispute. |
| submitter_agent_id | integer | optional | Arbiter id of the agent submitting this dispute. Must exist — register first via POST /api/agents. |
| fault_agent_id | integer | optional | Arbiter id of the agent believed to be at fault. If omitted, Arbiter determines fault from the chain. |
Chain Hop Object
| Field | Type | Required | Description |
|---|---|---|---|
| agent_id | string | required | Your external agent identifier. |
| action | string | required | What this agent did at this hop (e.g. initiated_purchase, delivered_output, failed_delivery). |
| timestamp | string | required | ISO 8601 timestamp of the action. |
| amount | number | optional | Dollar value of this hop (for settlement calculations). |
| outcome | string | optional | success or failed. |
| error | string | optional | Error code or message if outcome is failed. |
| metadata | object | optional | Arbitrary additional context for this hop. |
Response
{
"dispute_id": 1,
"status": "open",
"submitted_at": "2026-04-23T10:00:00.000Z",
"transaction_chain": {
"id": 1,
"dispute_id": 1,
"chain_data": [ /* your submitted hops */ ],
"created_at": "2026-04-23T10:00:00.000Z"
}
}
Status Codes
201 Created 400 Validation error 500 Server errorReturns paginated disputes with agent metadata. Supports filtering by status, agent, and date range. Max 100 results per page.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | optional | Filter by dispute status. One of: open, investigating, resolved, escalated. |
| agent_id | integer | optional | Filter by agent (matches either submitter or fault agent). |
| from | string | optional | Start of date range. ISO 8601 (e.g. 2026-04-01). |
| to | string | optional | End of date range. ISO 8601. |
| page | integer | optional | Page number, 1-indexed. Default: 1. |
| limit | integer | optional | Results per page. Default: 20. Max: 100. |
Example
curl "https://arbiter-2.polsia.app/api/disputes?status=open&limit=50" \ -H "Authorization: Bearer arb_live_..."
Response
{
"disputes": [
{
"id": 1,
"status": "open",
"description": "Agent C delivered corrupt data payload",
"submitter_agent_id": 42,
"submitter_agent_name": "BuyerBot",
"submitter_external_id": "agent-buyer-001",
"fault_agent_id": null,
"fault_agent_name": null,
"submitted_at": "2026-04-23T10:00:00.000Z",
"updated_at": "2026-04-23T10:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1,
"total_pages": 1
}
}
Status Codes
200 OK 400 Invalid filter value 500 Server errorReturns the full dispute record including agent metadata, the transaction chain, and any resolutions.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integer | Dispute ID returned from POST /api/disputes. |
Example
curl https://arbiter-2.polsia.app/api/disputes/1 \ -H "Authorization: Bearer arb_live_..."
Response
{
"id": 1,
"status": "resolved",
"description": "Agent C delivered corrupt data payload",
"submitter_agent_id": 42,
"submitter_agent_name": "BuyerBot",
"submitter_external_id": "agent-buyer-001",
"submitter_platform": "sapiom",
"fault_agent_id": 44,
"fault_agent_name": "DataBot",
"fault_external_id": "agent-data-003",
"fault_platform": "sapiom",
"submitted_at": "2026-04-23T10:00:00.000Z",
"updated_at": "2026-04-23T10:00:05.000Z",
"transaction_chains": [
{
"id": 1,
"dispute_id": 1,
"chain_data": [ /* hops */ ],
"created_at": "2026-04-23T10:00:00.000Z"
}
],
"resolutions": [
{
"id": 1,
"dispute_id": 1,
"action": "full_refund",
"fault_agent_id": 44,
"reasoning": "Agent C failed to deliver required output",
"created_at": "2026-04-23T10:00:05.000Z"
}
]
}
Status Codes
200 OK 400 Invalid ID format 404 Dispute not found 500 Server errorReturns the resolution(s) for a dispute. Returns 404 if no resolution exists yet — the dispute is still being processed. Poll this endpoint after submitting a dispute to check for completion.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integer | Dispute ID. |
Resolution Actions
| Action | Meaning |
|---|---|
| full_refund | Fault agent owes 100% of transaction value to submitting agent. |
| partial_credit | Partial value returned. See resolution.metadata for amount. |
| escalation | Dispute could not be resolved algorithmically. Requires human review. |
| no_fault | Chain analysis found no clear fault. No action taken. |
Example
curl https://arbiter-2.polsia.app/api/disputes/1/resolution \ -H "Authorization: Bearer arb_live_..."
Response
{
"dispute_id": 1,
"dispute_status": "resolved",
"resolutions": [
{
"id": 1,
"dispute_id": 1,
"action": "full_refund",
"fault_agent_id": 44,
"reasoning": "Agent C failed to deliver required output",
"metadata": {},
"created_at": "2026-04-23T10:00:05.000Z"
}
]
}
Not Yet Resolved (404)
{
"error": "No resolution found for this dispute",
"dispute_id": 1,
"dispute_status": "investigating"
}
Status Codes
200 Resolution found 404 No resolution yet or dispute not found 500 Server errorExecute a Stripe payment settlement for a resolved dispute. Requires STRIPE_SECRET_KEY configured on the server. Supports three settlement types: refund (buyer wins), charge (seller wins), and split (shared fault). All amounts are in cents.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| dispute_id | integer | ✅ | Arbiter dispute ID. Must be resolved. |
| amount_cents | integer | ✅ | Settlement amount in cents (min: 1). |
| settlement_type | string | ✅ | One of: refund, charge, split. |
| stripe_payment_intent_id | string | For refund/split | Stripe payment intent ID from the original transaction. |
| fault_agent_id | integer | Optional | Arbiter agent ID of the party at fault. |
| fault_share_cents | integer | For split | Fault agent's payment share (cents). Used in split settlements. |
| buyer_share_cents | integer | For split | Buyer's refund share (cents). Used in split settlements. |
| idempotency_key | string | Optional | Unique key to prevent duplicate settlements. Re-submitting the same key for the same dispute returns the existing settlement. |
Example: Refund (buyer wins)
curl -X POST https://arbiter-2.polsia.app/api/settlements \\ -H \"Authorization: Bearer arb_live_...\" \\ -H \"Content-Type: application/json\" \\ -d '{ \"dispute_id\": 42, \"amount_cents\": 5000, \"settlement_type\": \"refund\", \"stripe_payment_intent_id\": \"pi_xxx\", \"idempotency_key\": \"dispute-42-full-refund\" }'
Response
{
\"id\": 1,
\"dispute_id\": 42,
\"settlement_type\": \"refund\",
\"status\": \"succeeded\",
\"amount_cents\": 5000,
\"stripe_payment_intent_id\": \"pi_xxx\",
\"stripe_refund_id\": \"re_xxx\",
\"settled_at\": \"2026-04-29T12:30:00.000Z\",
\"created_at\": \"2026-04-29T12:30:00.000Z\"
}
Status Codes
201 Settlement executed 400 Validation error or unresolved dispute 404 Dispute not found 502 Stripe API error (check stripe_error in response) 503 Stripe not configuredList all settlements with optional filtering by dispute or status.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| dispute_id | integer | Filter by dispute ID. |
| status | string | Filter by status: pending, succeeded, failed, cancelled. |
| page | integer | Page number. Default: 1. |
| limit | integer | Results per page. Default: 50. Max: 100. |
Example
curl https://arbiter-2.polsia.app/api/settlements?dispute_id=42 \\ -H \"Authorization: Bearer arb_live_...\"
Response
{
\"settlements\": [
{
\"id\": 1,
\"dispute_id\": 42,
\"settlement_type\": \"refund\",
\"status\": \"succeeded\",
\"amount_cents\": 5000,
\"stripe_refund_id\": \"re_xxx\"
}
],
\"pagination\": {
\"page\": 1,
\"limit\": 50,
\"total\": 1,
\"total_pages\": 1
}
}
Returns a single settlement by ID including Stripe transaction details.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integer | Settlement ID returned from POST /api/settlements. |
Response
{
\"id\": 1,
\"dispute_id\": 42,
\"settlement_type\": \"refund\",
\"status\": \"succeeded\",
\"amount_cents\": 5000,
\"stripe_payment_intent_id\": \"pi_xxx\",
\"stripe_refund_id\": \"re_xxx\",
\"fault_agent_id\": 44,
\"settled_at\": \"2026-04-29T12:30:00.000Z\",
\"created_at\": \"2026-04-29T12:30:00.000Z\"
}
Status Codes
200 Settlement found 404 Settlement not foundError Codes
All errors return JSON with an error string. HTTP status codes follow standard semantics.
| Status | Error | Cause |
|---|---|---|
| 400 | Missing required fields: ... |
One or more required fields omitted from the request body. |
| 400 | chain_data must be an array |
chain_data was sent as a non-array value. |
| 400 | chain_data[n] must include agent_id, action, and timestamp |
A hop in the chain is missing a required field. |
| 400 | submitter_agent_id N not found |
The referenced agent has not been registered. Call POST /api/agents first. |
| 400 | Invalid status. Must be one of: ... |
Unknown dispute status passed to the filter. |
| 400 | Invalid "from" date format |
Date string could not be parsed. Use ISO 8601. |
| 400 | Invalid input type. |
A field received the wrong type (e.g. string instead of integer for an ID). |
| 404 | Dispute not found |
No dispute exists with the given ID. |
| 404 | No resolution found for this dispute |
Dispute exists but resolution is not yet available. Poll again. |
| 409 | Agent with this external_agent_id already exists |
Duplicate agent registration. Use the returned agent_id. |
| 409 | Duplicate entry. Resource already exists. |
Unique constraint violation on another field. |
| 500 | Internal server error |
Unexpected server error. Retry with exponential backoff. |
Rate Limits
Rate limit headers are included in every response:
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 97 X-RateLimit-Reset: 1745510460
When you exceed the limit, Arbiter returns 429 Too Many Requests. Back off and retry after the timestamp in X-RateLimit-Reset.
Need higher limits for high-throughput agent platforms? Contact us — enterprise limits are available.
JavaScript / TypeScript SDK
A typed SDK is available for Node.js and TypeScript. Wraps all API endpoints with typed request/response objects.
Install
npm install arbiter-client
Usage
import { ArbiterClient } from 'arbiter-client'; const arbiter = new ArbiterClient({ apiKey: 'arb_live_your_key_here', baseUrl: 'https://arbiter-2.polsia.app' // optional, defaults to production }); // Register an agent const agent = await arbiter.registerAgent({ external_agent_id: 'my-agent-001', name: 'MyBot', platform: 'sapiom' }); // Submit a dispute const dispute = await arbiter.submitDispute([ { agent_id: 'my-agent-001', action: 'initiated_purchase', timestamp: '2026-04-23T10:00:00Z' }, { agent_id: 'their-agent-002', action: 'failed_delivery', timestamp: '2026-04-23T10:01:00Z', outcome: 'failed' } ]); // Poll for resolution const resolution = await arbiter.getResolution(dispute.dispute_id);
The SDK source is available in the /sdk directory of the Arbiter repository.