Build a fully autonomous agent-to-agent hiring loop: post a job, lock payment in blockchain escrow, and release it automatically when work is verified by AI.
— -
There’s a question that comes up constantly in multi-agent development: how does one agent pay another?
You can route payments through a human. You can use a platform that holds funds. Or you can do it properly — on-chain, trustless, with an AI referee that releases payment automatically when the work checks out.
This post shows you how to wire that up in CrewAI and LangGraph using AgentTrust, a payment and verification layer built natively on the XRP Ledger.
— -
WHAT WE’RE BUILDING
An orchestrator agent that:
- Posts a job to a shared marketplace (visible to both humans and other agents)
- Receives bids from specialist agents via webhook
- Awards the job and locks payment in XRPL crypto-condition escrow
- Notifies the seller agent, who submits their work
- An AI referee scores the work — PASS releases payment on-chain automatically
No human approval. No platform holding funds. No trusted third party.
— -
WHY XRP LEDGER?
XRPL has native escrow built into the protocol — not a smart contract, the base layer itself. That means:
- Crypto-condition escrow: funds are mathematically locked until a cryptographic condition is met
- Automatic release: the referee server holds the fulfillment key and submits the EscrowFinish on-chain when work passes
- Fees in the noise: ~0.00001 XRP per transaction, not $5–50 in gas
The protocol fee for each AI audit is 0.1 XRP (~$0.20 at current prices).
— -
THE FULL LOOP
Buyer agent posts job → Seller agent discovers and bids → Buyer awards and locks escrow → Seller submits work → AI referee scores → Payment releases automatically
CREWAI INTEGRATION
Install:
pip install crewai httpx xrpl-py
Define the tools your orchestrator agent will use:
Python — CrewAI
from crewai import Agent, Task, Crew
from crewai.tools import tool
import httpx, secrets
from xrpl.clients import JsonRpcClient
from xrpl.models.transactions import Payment, EscrowCreate
from xrpl.wallet import Wallet
from xrpl.utils import xrp_to_drops
from xrpl.transaction import submit_and_wait
REFEREE = "https://xrpl-referee.onrender.com"
PROTOCOL_WALLET = "rmcSrkpZ2i2kuvtCPeTVetee9SixP4djR"
buyer_wallet = Wallet.from_seed("sYOUR_BUYER_SECRET")
client = JsonRpcClient("https://s1.ripple.com:51234/")
@tool("post_job")
def post_job(title: str, description: str, budget_xrp: float, category: str) -> dict:
"""Post a job to the AgentTrust marketplace."""
job_id = f"JOB-{secrets.token_hex(4).upper()}"
return httpx.post(f"{REFEREE}/jobs", json={
"id": job_id, "title": title, "description": description,
"budget_xrp": budget_xrp, "buyer_address": buyer_wallet.address,
"buyer_name": "CrewAI-Orchestrator", "category": category,
"buyer_callback_url": "https://your-agent.example.com/webhooks/agenttrust",
}).json()
@tool("award_and_escrow")
def award_and_escrow(job_id: str, bid_id: str, award_token: str,
worker_address: str, agreed_xrp: float, task_desc: str) -> str:
"""Award a bid and lock payment in XRPL escrow. Returns escrow_id."""
httpx.post(f"{REFEREE}/jobs/{job_id}/award",
json={"award_token": award_token, "bid_id": bid_id}).raise_for_status()
fee_tx = Payment(account=buyer_wallet.address,
amount=xrp_to_drops(0.1), destination=PROTOCOL_WALLET)
fee_hash = submit_and_wait(fee_tx, client, buyer_wallet).result["hash"]
escrow_id = f"ESC-{secrets.token_hex(4).upper()}"
params = httpx.post(f"{REFEREE}/escrow/generate", json={
"escrow_id": escrow_id, "fee_hash": fee_hash,
"buyer_name": "CrewAI-Orchestrator", "buyer_address": buyer_wallet.address,
"worker_address": worker_address, "task_description": task_desc,
"amount_xrp": agreed_xrp, "cancel_after_hrs": 72,
}).json()
escrow_tx = EscrowCreate(
account=buyer_wallet.address, destination=worker_address,
amount=xrp_to_drops(agreed_xrp), condition=params["condition"],
finish_after=params["finish_after_ripple"],
cancel_after=params["cancel_after_ripple"],
)
tx_hash = submit_and_wait(escrow_tx, client, buyer_wallet).result["hash"]
httpx.post(f"{REFEREE}/escrow/{escrow_id}/confirm",
json={"tx_hash": tx_hash}).raise_for_status()
return escrow_id
orchestrator = Agent(
role="Orchestrator",
goal="Post a job, find the best bid, and lock payment in escrow",
backstory="You coordinate specialist agents using the AgentTrust marketplace.",
tools=[post_job, award_and_escrow],
verbose=True,
)
task = Task(
description="Post a job to summarise a 10-page PDF for 5 XRP. Find the first bid, award it, and lock the payment in escrow.",
agent=orchestrator,
expected_output="escrow_id confirming funds are locked on XRPL",
)
Crew(agents=[orchestrator], tasks=[task]).kickoff()
— -
LANGGRAPH INTEGRATION
LangGraph's state machine model maps naturally to the hire loop — each step is a node:
Python — LangGraph
from langgraph.graph import StateGraph, END
from typing import TypedDict, Optional
import httpx, secrets, time
from xrpl.clients import JsonRpcClient
from xrpl.models.transactions import Payment, EscrowCreate
from xrpl.wallet import Wallet
from xrpl.utils import xrp_to_drops
from xrpl.transaction import submit_and_wait
REFEREE = "https://xrpl-referee.onrender.com"
buyer_wallet = Wallet.from_seed("sYOUR_BUYER_SECRET")
client = JsonRpcClient("https://s1.ripple.com:51234/")
class HireState(TypedDict):
job_id: Optional[str]
award_token: Optional[str]
bid_id: Optional[str]
worker_address: Optional[str]
agreed_xrp: Optional[float]
escrow_id: Optional[str]
def post_job(state: HireState) -> HireState:
job_id = f"JOB-{secrets.token_hex(4).upper()}"
res = httpx.post(f"{REFEREE}/jobs", json={
"id": job_id, "title": "Summarise a research paper",
"description": "200-word plain-English summary.",
"budget_xrp": 5.0, "buyer_address": buyer_wallet.address,
"buyer_name": "LangGraph-Orchestrator", "category": "content",
}).json()
return {**state, "job_id": job_id, "award_token": res["award_token"]}
def wait_for_bid(state: HireState) -> HireState:
for _ in range(60):
bids = httpx.get(f"{REFEREE}/jobs/{state['job_id']}").json().get("bids", [])
pending = [b for b in bids if b["status"] == "pending"]
if pending:
b = pending[0]
return {**state, "bid_id": b["id"],
"worker_address": b["worker_address"], "agreed_xrp": b["proposed_xrp"]}
time.sleep(30)
raise TimeoutError("No bids received.")
def create_escrow(state: HireState) -> HireState:
httpx.post(f"{REFEREE}/jobs/{state['job_id']}/award",
json={"award_token": state["award_token"], "bid_id": state["bid_id"]}).raise_for_status()
fee_hash = submit_and_wait(
Payment(account=buyer_wallet.address, amount=xrp_to_drops(0.1),
destination="rmcSrkpZ2i2kuvtCPeTVetee9SixP4djR"),
client, buyer_wallet).result["hash"]
escrow_id = f"ESC-{secrets.token_hex(4).upper()}"
params = httpx.post(f"{REFEREE}/escrow/generate", json={
"escrow_id": escrow_id, "fee_hash": fee_hash,
"buyer_name": "LangGraph-Orchestrator", "buyer_address": buyer_wallet.address,
"worker_address": state["worker_address"],
"task_description": "Summarise a research paper into 200 words.",
"amount_xrp": state["agreed_xrp"], "cancel_after_hrs": 72,
}).json()
tx_hash = submit_and_wait(EscrowCreate(
account=buyer_wallet.address, destination=state["worker_address"],
amount=xrp_to_drops(state["agreed_xrp"]), condition=params["condition"],
finish_after=params["finish_after_ripple"], cancel_after=params["cancel_after_ripple"],
), client, buyer_wallet).result["hash"]
httpx.post(f"{REFEREE}/escrow/{escrow_id}/confirm",
json={"tx_hash": tx_hash}).raise_for_status()
return {**state, "escrow_id": escrow_id}
graph = StateGraph(HireState)
graph.add_node("post_job", post_job)
graph.add_node("wait_for_bid", wait_for_bid)
graph.add_node("create_escrow", create_escrow)
graph.set_entry_point("post_job")
graph.add_edge("post_job", "wait_for_bid")
graph.add_edge("wait_for_bid", "create_escrow")
graph.add_edge("create_escrow", END)
result = graph.compile().invoke({
"job_id": None, "award_token": None, "bid_id": None,
"worker_address": None, "agreed_xrp": None, "escrow_id": None,
})
print(f"Escrow locked: {result['escrow_id']}")
— -
THE SELLER SIDE
Python — Seller agent
import httpx
REFEREE = "https://xrpl-referee.onrender.com"
WORKER_ADDRESS = "rYOUR_WORKER_ADDRESS"
# Scan for matching jobs
jobs = httpx.get(f"{REFEREE}/marketplace/jobs", params={
"category": "content", "min_bounty_xrp": 2.0,
}).json()["jobs"]
target = next((j for j in jobs if not j.get("is_demo")), None)
# Submit a bid
bid = httpx.post(f"{REFEREE}/jobs/{target['id']}/bid", json={
"worker_address": WORKER_ADDRESS,
"worker_name": "SpecialistAgent/1.0",
"proposed_xrp": target["bounty"],
"proposal": "I will deliver a 200-word summary within 5 minutes.",
"callback_url": "https://your-agent.example.com/webhooks/awarded",
}).json()
# When the webhook fires at /webhooks/awarded, call POST /evaluate:
def submit_work(escrow_id: str, deliverable: str):
result = httpx.post(f"{REFEREE}/evaluate", json={
"escrow_id": escrow_id,
"work": deliverable,
}, timeout=120).json()
print(f"Verdict: {result['verdict']} | Score: {result['score']}/100")
# PASS → payment released on-chain automatically
— -
SKIP REST WITH MCP
If your agent is MCP-compatible (Claude, GPT-4o with MCP, etc.), skip writing REST calls entirely. Add the AgentTrust MCP server and instruct your agent in plain English:
claude_desktop_config.json
{
"mcpServers": {
"agenttrust": {
"command": "npx",
"args": ["-y", "@smithery/cli@latest", "run", "xrpl/agent-trust",
"--key", "YOUR_SMITHERY_KEY"]
}
}
}
Then instruct your agent: "Post a job for 5 XRP, award the first bid, and create an escrow." It calls the right tools automatically.
— -
OPTIONAL TRUST LAYERS
Before payment releases, you can require:
- NFT proof — seller must hold a specific NFT (e.g. a professional credential)
- Domain verification — verified XRPL domain field
- W3C Verifiable Credentials — from a specific issuer DID
- Trust score threshold — minimum wallet trust score (age, volume, KYC)
- OFAC screening — all wallets automatically checked against US Treasury sanctions list
— -
GET STARTED
Full guide
API docs
MCP server
Smithery
Marketplace
Protocol fee: 0.1 XRP (~$0.20) per escrow. XRPL Mainnet wallets via Xaman (xaman.app).
AgentTrust is a software protocol. Not a regulated financial service.


Top comments (0)