Skip to main content

Validation API

Validation API

This guide covers how to call the Arbiter validation API, interpret results, and handle errors.

When to Use This

  • You have a user intent (free-form text).
  • You have a candidate transaction payload.
  • You want a verification result (PASS or REJECT) with node-level reasoning.

Prerequisites

  • Arbiter-Core dependencies installed.
  • API server running.

Start locally:

python -m api.server

Default URL: http://localhost:8000

Endpoints

  • GET /health returns basic server and LLM status.
  • POST /validate runs full validation.

POST /validate Request

{
"human_intent": "string (required)",
"proposed_tx": {
"protocol": "optional but strongly recommended",
"to": "0x...",
"data": "0x...",
"value": "string-or-number",
"gas": "string-or-number",
"metadata": {},
"context": {},
"order": {},
"transactions": []
},
"metadata": {},
"preferences": {
"slippage_bps": 0,
"aggressiveness": 0.5,
"protocol_allowlist": ["uniswap"]
},
"return_prompts": false
}

Field notes:

  • human_intent is required.
  • proposed_tx defaults to {} if omitted, but practical validation needs real transaction fields.
  • proposed_tx.protocol is optional (auto-detection exists), but sending it reduces ambiguity.
  • Top-level metadata is passed into validation context.
  • preferences is accepted by the API schema but not actively enforced in validator logic yet.

POST /validate Response

{
"decision": "PASS | REJECT",
"reason": "string",
"protocol": "string|null",
"primary_failure_node": "string|null",
"llm_calls": 0,
"results": {
"node.id": {
"status": "PASS|FAIL|SKIP",
"confidence": 0.0,
"reasoning": "string",
"details": {}
}
},
"extracted_elements": {},
"context": {},
"explanation": {
"summary": "string",
"decision": "PASS|REJECT",
"key_issues": [],
"affected_nodes": {},
"confidence_summary": {},
"recommendations": [],
"metadata": {}
}
}

Interpreting Results

  • decision is the final verdict: PASS or REJECT.
  • reason is the top-level explanation from the first relevant failure (or a pass summary).
  • results contains per-node verdicts and details.
  • primary_failure_node identifies the key failing node used for the decision narrative.
  • llm_calls shows semantic-node call count, useful for debugging and cost visibility.

Node Statuses

Each node in results reports one of three statuses:

  • PASS: the check succeeded.
  • FAIL: the check failed.
  • SKIP: the check was intentionally skipped or lacked the required context.

primary_failure_node points to the main failing node used for top-level reasoning.

Examples

ERC-20 Transfer (curl)

curl -X POST "http://localhost:8000/validate" \
-H "Content-Type: application/json" \
-d '{
"human_intent": "Transfer 100 USDC to 0x000000000000000000000000000000000000dEaD",
"proposed_tx": {
"protocol": "transfer",
"to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"data": "0xa9059cbb000000000000000000000000000000000000000000000000000000000000dead0000000000000000000000000000000000000000000000000000000005f5e100",
"value": "0",
"gas": "65000"
}
}'

Native ETH Transfer (curl)

curl -X POST "http://localhost:8000/validate" \
-H "Content-Type: application/json" \
-d '{
"human_intent": "Send 0.1 ETH to 0x000000000000000000000000000000000000dEaD",
"proposed_tx": {
"protocol": "transfer",
"to": "0x000000000000000000000000000000000000dEaD",
"value": "100000000000000000",
"gas": "21000"
}
}'

Python

import requests

url = "http://localhost:8000/validate"
payload = {
"human_intent": "Swap 500 USDC for ETH with max slippage 0.5%",
"proposed_tx": {
"protocol": "uniswap",
"to": "0x...",
"data": "0x...",
"value": "0"
},
"metadata": {"from_address": "0x..."}
}

resp = requests.post(url, json=payload, timeout=30)
print(resp.status_code)
print(resp.json())

Error Handling

There are two categories of failure to handle.

API/Transport Errors (HTTP Error Codes)

The request could not be processed by the server.

Status CodeMeaning
422Request schema or type validation failed.
503Validator not ready (startup or initialization issue).
500Unexpected server exception.

Error response shape:

{
"detail": "error message"
}

Validation Rejections (HTTP 200 with REJECT)

The API call succeeded, but the proposed transaction did not satisfy validation rules. This is a product-level or domain-level error, not a network or server failure.

Example response:

{
"decision": "REJECT",
"reason": "Operation mismatch ...",
"primary_failure_node": "intent_alignment.operation_matching",
"results": {
"intent_alignment.operation_matching": {
"status": "FAIL",
"confidence": 0.9,
"reasoning": "...",
"details": {}
}
}
}

Client Handling Strategy

  1. If the HTTP status is not 2xx, handle by status code (422, 503, 500). Retry only on transient server conditions such as 503 or intermittent 500 errors.
  2. If the HTTP status is 200, read decision. If it is REJECT, inspect primary_failure_node, reason, and node details. Show remediation guidance to the user, or rebuild the transaction and re-validate.

Retry Guidance

Retry with backoff for:

  • 503 when the Arbiter is not ready
  • Transient 500 conditions

Do not retry for:

  • 422 malformed request errors
  • REJECT decisions caused by deterministic rule failures

Remediation by Failure Type

  • intent_alignment.* failures: Make the intent and transaction consistent in action, token, amount, deadline, and slippage.
  • technical_invariants.* failures: Fix transaction encoding, format, protocol parameters, or gas.
  • legal_compliance.* failures: Use supported assets and addresses, and ensure policy-compliant amounts.
  • adversarial_detection.* failures: Tighten parameters, remove suspicious patterns, and add explicit user constraints.

Operational Notes

  • The LLM may be disabled. In that case, semantic capability is reduced, but the API still works.
  • llm_calls helps monitor semantic workload.
  • explanation may be absent (null) if explanation construction fails. Rely on reason and results as a fallback.

Logging Recommendations

Persist at least the following for each validation call:

  • Request ID or transaction hash (if available)
  • decision
  • reason
  • protocol
  • primary_failure_node
  • Failing node details from results
  • HTTP status and retry count

This makes support triage and rule tuning significantly easier.