Developer Reference

Documentation

API reference for the RSoft Bank protocol. Read endpoints (explorer, status, history, rates) are public; borrowing endpoints (loan request, credit-line draw) require an API key. A2A uses agent signatures.

Quickstart - your agent's first loan in ~15 minutes

The full cycle: register an on-chain identity, borrow 5 USDC, repay it, and walk away with the thing that actually matters - verifiable on-chain credit history your agent can present to any lender that speaks ERC-8004.

1 · Wallet

An agentic wallet (Coinbase CDP recommended) with a few cents of ETH on Base for gas.

2 · Passport

A one-time ERC-8004 register() from the agent's own wallet - snippets on the Register page.

3 · Pilot API key

REST borrowing uses an API key during the pilot - ping @RSoft-Agentic-Bank to get one. A2A and MCP need no key.

# pip install cdp-sdk requests
# Env: CDP_API_KEY_ID / CDP_API_KEY_SECRET / CDP_WALLET_SECRET (your agent's
# CDP Server Wallet) + BANK_API_KEY (pilot key) + AGENT_WALLET (0x…)
import asyncio, os, time, uuid, requests
from cdp import CdpClient
from cdp.openapi_client.models.eip712_domain import EIP712Domain
from cdp.evm_transaction_types import TransactionRequestEIP1559

BANK   = "https://rsoft-agentic-bank.com/api/v1"
KEY    = {"X-API-Key": os.environ["BANK_API_KEY"]}
WALLET = os.environ["AGENT_WALLET"]
USDC   = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"          # Base mainnet
VERIFYING = "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"       # EIP-712 domain

async def main():
    async with CdpClient(api_key_id=os.environ["CDP_API_KEY_ID"],
                         api_key_secret=os.environ["CDP_API_KEY_SECRET"],
                         wallet_secret=os.environ["CDP_WALLET_SECRET"]) as cdp:

        # 1) Sign the loan terms (EIP-712 LoanRequest) with the agent's wallet
        amount, nonce, deadline = 5.0, str(uuid.uuid4()), int(time.time()) + 3600
        domain = EIP712Domain(name="RSoft Agentic Bank", version="1",
                              chain_id=8453, verifying_contract=VERIFYING)
        # NOTE: CDP requires the EIP712Domain entry inside `types` (ethers/viem omit it)
        types = {
            "EIP712Domain": [
                {"name": "name",              "type": "string"},
                {"name": "version",           "type": "string"},
                {"name": "chainId",           "type": "uint256"},
                {"name": "verifyingContract", "type": "address"}],
            "LoanRequest": [
                {"name": "agentWallet",     "type": "address"},
                {"name": "loanAmountUsdc6", "type": "uint256"},
                {"name": "nonce",           "type": "string"},
                {"name": "deadline",        "type": "uint256"}]}
        message = {"agentWallet": WALLET, "loanAmountUsdc6": int(amount * 1e6),
                   "nonce": nonce, "deadline": deadline}
        sig = await cdp.evm.sign_typed_data(address=WALLET, domain=domain,
                                            types=types, primary_type="LoanRequest",
                                            message=message)

        # 2) Request the loan — the 5-agent pipeline runs and disburses USDC
        r = requests.post(f"{BANK}/loan/request", headers=KEY, json={
            "agent_wallet": WALLET, "loan_amount": amount,
            "nonce": nonce, "deadline": deadline, "signature": sig}).json()
        request_id = r["request_id"]

        # 3) Poll until disbursed (public endpoint, no key)
        while requests.get(f"{BANK}/loan/status/{request_id}").json()["status"] \
                not in ("disbursed", "rejected"):
            time.sleep(5)

        # 4) Repay: quote is public; pay the EXACT amount to the treasury
        info = requests.get(f"{BANK}/loan/repay-info/{WALLET}").json()
        base6 = int(round(info["repayment_amount"] * 1e6))
        data = ("0xa9059cbb" + info["pay_to"][2:].zfill(64)
                             + hex(base6)[2:].zfill(64))       # ERC-20 transfer
        tx = await cdp.evm.send_transaction(address=WALLET, network="base",
                transaction=TransactionRequestEIP1559(to=USDC, data=data, value=0))

        # 5) Report it (optional — unreported payments are auto-detected ~10 min)
        requests.post(f"{BANK}/loan/repay", headers=KEY,
                      json={"request_id": request_id, "tx_hash": tx})
        print("Loan repaid - your agent now has on-chain credit history ✓")

asyncio.run(main())

What your agent earned: a repaid loan recorded in the bank's books and a positive ERC-8004 reputation mark signed by the bank's wallet - portable, verifiable, and impossible to self-fabricate. Each repayment also climbs the credit ladder: $5 → $10 (1 repaid) → $25 (3) → $50 (6) → $100 (10). Check any agent's standing on the Reputation page.

Getting Started

What is RSoft Bank?

RSoft Bank is a decentralized lending protocol designed for AI agents. Autonomous agents can request USDC loans that are evaluated through an automated multi-agent pipeline - from identity verification to on-chain settlement.

Base URL

https://rsoft-agentic-bank.com

All endpoints are prefixed with /api/v1 except health checks.

Authentication

All read endpoints listed here are public - no API key or wallet connection required. Responses are JSON format with ISO 8601 timestamps.

Agent quickstart · one prompt

Paste this into Claude Code, Cursor, Windsurf, Codex, OpenClaw or any agent that can read a URL. It loads the bank's skill manifest and walks the agent through setup, signing and repayment.

I want my AI agent to get credit from RSoft Bank. Read the docs at https://rsoft-agentic-bank.com/skills.md and then set it up.

Or add the MCP server directly:

claude mcp add --transport http rsoft-bank https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/mcp

Machine-readable index for LLMs and crawlers: /llms.txt · /skills.md

How Agents Borrow

An agent can originate debt through four surfaces. REST, MCP and A2A are one-shot loans that share the same underwriting (caps, EIP-712 signature, replay-protected nonce); the credit line is revolving.

REST
POST /api/v1/loan/request

Direct REST

Simplest path. Sign the loan terms and POST them. Pilot API key - see Quickstart.

Sign the EIP-712 LoanRequest (agentWallet, loanAmountUsdc6, nonce, deadline) and POST it. The bank runs the full 5-agent pipeline and disburses USDC to your wallet.

POST /api/v1/loan/request
X-API-Key: <bank_api_key>

{
  "agent_wallet": "0x…",
  "loan_amount": 5,
  "nonce": "…",
  "deadline": 1893456000,
  "signature": "0x…"      // EIP-712 LoanRequest
}
MCP
tool: request_loan

MCP tool

For autonomous agents that already use an MCP toolset. No API key needed.

Add the bank's MCP server to your agent's tools and call request_loan with your EIP-712 signature. Same underwriting and signature contract as REST - the MCP transports your signature, it never signs for you. See the MCP Server section for the full toolset.

// agent MCP config (Streamable HTTP)
mcpServers:
  rsoft-bank:
    url: https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/mcp

// then your agent calls the tool
tool  request_loan
args  { "amount": 5, "agent_id": "0x…",
        "signature": "0x…", "nonce": "…", "deadline": 1893456000 }
A2A
SendMessage: negotiate_loan → request_loan

Agent-to-Agent

For agents speaking the A2A 1.0 standard. Discover the agent card, delegate the task.

The bank is a standard A2A peer: discover it via its Agent Card, preview terms with negotiate_loan, sign them and execute with request_loan. See the A2A Protocol section for the full skill set.

// discovery
GET  <a2a-server>/.well-known/agent-card.json

// delegate (JSON-RPC, header A2A-Version: 1.0)
POST <a2a-server>/
{ "jsonrpc": "2.0", "id": 1, "method": "SendMessage",
  "params": { "message": { "role": "ROLE_USER", "parts": [
    { "data": { "skill": "negotiate_loan",
                "agent_id": "0x…", "amount": 5 } } ]}}}
Credit Line
POST /credit-lines/request → /{id}/draw

Revolving credit

For agents with recurring capital needs.

Open an approved credit line once, then draw against it repeatedly during the window instead of requesting a new loan each time. Repay to restore available credit.

// open a line (once)
POST /api/v1/credit-lines/request
{ "agent_id": "0x…", "requested_limit": 50 }

// draw against it (repeat, owner-signed)
POST /api/v1/credit-lines/{line_id}/draw
{ "amount": 5, "signature": "0x…" }

Repaying a Loan

Repayment is a plain USDC transfer to the treasury for the exact owed amount (principal + full-term interest - fixed at origination, so the quote never changes). Two steps, and the second one is optional.

GET
/api/v1/loan/repay-info/{wallet}

1 · Get the repayment quote

Public - no API key.

Returns exactly what the agent owes and where to send it.

GET /api/v1/loan/repay-info/0xYourAgentWallet

{
  "request_id": "req_…",
  "principal": 5.0,
  "interest": 0.102739,
  "repayment_amount": 5.102739,
  "currency": "USDC",
  "pay_to": "0x274C…74C5a"      // bank treasury (Base)
}

Send a USDC transfer from the agent's own wallet (the sender is verified - nobody can claim your payment) to pay_to for the exact repayment_amount.

POST
/api/v1/loan/repay

2 · Report the payment (optional fast path)

API key · settles instantly.

The bank verifies the transaction on-chain (token, recipient, sender, amount) before crediting - a tx hash can settle exactly one debt, ever.

POST /api/v1/loan/repay
X-API-Key: <bank_api_key>

{
  "request_id": "req_…",
  "tx_hash": "0x…"        // your USDC transfer
}

Paying alone is enough

If your agent dies between the transfer and the report, nothing bad happens: the bank sweeps incoming treasury transfers every ~10 minutes and credits any exact-amount payment from a borrower automatically. An agent that paid can never be marked in default. Every verified repayment updates the agent's standing (credit ladder) and posts a positive, bank-signed ERC-8004 reputation mark - the portable credit history other lenders can verify.

Webhooks - loan events, pushed

Subscribe an HTTPS endpoint to loan lifecycle events instead of polling /loan/status. Deliveries are HMAC-signed. Delivery never gates a loan: a failing endpoint does not delay or block origination, disbursement or repayment.

Subscribe

POST /api/v1/webhooks
X-API-Key: <bank_api_key>

{
  "url": "https://agent.example.com/hooks/rsoft",   // https, no private hosts
  "events": ["loan.disbursed", "loan.repaid", "loan.defaulted"],
  "agent_wallet": "0x…"                              // optional: scope to one wallet
}

→ 201
{ "id": "whk_…", "secret": "…" }     // the secret is returned ONCE - store it

The bank's API keys are shared, not per-agent, so a wallet-scoped subscription also requires that wallet's EIP-712 OwnerAction (action webhook_subscribe, resourceId = the url). Subscriptions for all agents need the bank admin key.

Events

loan.approved
loan.rejected
loan.disbursed
loan.repaid
loan.defaulted
loan.drafted
loan.draft_approved
loan.draft_rejected
loan.draft_expired

Manage

GET    /api/v1/webhooks?agent_wallet=0x…
DELETE /api/v1/webhooks/{id}
POST   /api/v1/webhooks/{id}/ping
GET    /api/v1/webhooks/{id}/deliveries

All with X-API-Key. ping sends a test delivery; deliveries lists attempts and responses.

Verify the signature

X-RSoft-Timestamp: 1756821731                 // unix seconds
X-RSoft-Signature: sha256=<hex>               // HMAC_SHA256(secret, "{timestamp}.{raw_body}")

// Node
import { createHmac, timingSafeEqual } from "node:crypto";
const expected = "sha256=" + createHmac("sha256", SECRET)
  .update(`${req.headers["x-rsoft-timestamp"]}.${rawBody}`).digest("hex");
const ok = timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-rsoft-signature"]));

Sign over the raw body, not a re-serialized one. Reject stale timestamps. Retries: 3 attempts with backoff; 4xx responses (except 408 and 429) are not retried.

Agent Directory - the ERC-8004 registry, readable

Public, keyless reads of the ERC-8004 Identity and Reputation registries on Base mainnet, joined with the bank's own books. Look up any agent by token id or wallet, list recent registrations, or search. Identity Registry 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432, Reputation Registry 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63.

GET /api/v1/agents/registry/58492

{
  "token_id": 58492,
  "exists": true,
  "owner": "0x4cff…",
  "agent_wallet": "0x4cff…",
  "canonical_uri": "https://…/agent.json",
  "client_count": 1,
  "clients": ["0xB684898D3f4437D93848456141445c66Aa322B13"],
  "known_issuers": [ ... ],       // issuers the bank recognises by name
  "trusted_feedback_count": 4,
  "trusted_feedback_value": ...,
  "chain_id": 8453,
  "identity_registry": "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  "reputation_registry": "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
  "bank": { ... }          // the bank's own credit standing, if the wallet is a customer
}
GET /api/v1/agents/registry/by-wallet/{wallet}
GET /api/v1/agents/registry/recent?limit=20
GET /api/v1/agents/registry/search?q=…

Limitation (by design)

The IdentityRegistry is not enumerable on mainnet. recent and search are a bounded scan of recent Registered events (default 5000 blocks) plus the bank's own customer table - not the full census. Responses carry scanned_window and limitation so callers can see exactly what was covered. Lookups by token id or wallet are exact.

MCP tools · and free REST twins on the MCP host

get_agent(token_id | wallet)     list_agents(limit)     search_agents(q)

GET https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/api/agents/{id|wallet}
GET https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/api/agents/recent
GET https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/api/agents/search?q=…

MCP Server - the bank as a toolset

The bank speaks the Model Context Protocol. Point any MCP-capable agent (Claude, LangGraph, AgentKit, eliza, …) at the server below and the full credit cycle - creditworthiness, borrow, repay - becomes callable tools. Connecting and calling tools needs no API key; the loan request still requires your agent's own EIP-712 signature (the MCP transports it, it never signs for you). The complete cycle has been exercised end-to-end on Base mainnet with real USDC.

Endpoint (Streamable HTTP)

https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/mcp

// agent MCP config
mcpServers:
  rsoft-bank:
    url: https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/mcp

Tools

get_creditworthiness(agent_id)

Credit score, history and outstanding debt for any agent. Use it before requesting - it tells you what the ladder will allow.

request_loan(amount, agent_id, signature, nonce, deadline)

Originates the loan. Sign the EIP-712 LoanRequest struct with the borrower wallet (see Quickstart step 1 - same struct, same domain) and pass signature + nonce + deadline. Unsigned requests are rejected. On approval the bank disburses USDC on Base to your wallet.

get_repayment_info(agent_id)

What you owe (principal + interest) and the treasury address to pay. Returns the request_id you'll need to confirm.

confirm_repayment(request_id, tx_hash)

After sending the exact USDC amount on-chain, report the tx hash. The bank verifies it on Base and marks the loan repaid. Forgot to call it? The treasury sweep auto-credits exact payments within ~10 minutes.

get_trust_score(wallet)

On-chain trust score (0-100) for ANY agent wallet, powered by RSoft Trust (beta) - vet a counterparty's ERC-8004 standing before trading or lending to it. See the Trust API section.

get_loan_status(request_id)

Status of a loan request, including amount, agent_wallet and a draft{…} block when the request is waiting on a sponsor. Poll it after a 202 draft response.

get_agent_controls(agent_id)

Sponsor binding, controls (paused, caps, draft mode) and the effective ceiling for an agent. Read it before requesting - it is the number the Gatekeeper will enforce. See Sponsor Controls.

get_agent(token_id | wallet)

ERC-8004 directory entry: owner, wallet, URI, reputation clients and the bank's own standing for that wallet. See Agent Directory.

list_agents(limit)

Recently registered agents - a bounded scan of recent Registered events plus the bank's customers, not the full census. The response says what window was scanned.

search_agents(q)

Search the same bounded window plus the bank's customer table. Same limitation, same scanned_window field.

Full cycle via MCP (Python)

# pip install mcp
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

MCP_URL = "https://7mavs5vu7ggbhtxvbavdgs26qa0cbawg.lambda-url.us-east-1.on.aws/mcp"

async def main():
    async with streamablehttp_client(MCP_URL) as (read, write, _):
        async with ClientSession(read, write) as s:
            await s.initialize()

            # 1) Borrow - signature/nonce/deadline come from YOUR wallet
            #    signing the EIP-712 LoanRequest (see Quickstart step 1).
            loan = await s.call_tool("request_loan", {
                "amount": 5.0, "agent_id": "0xYourAgentWallet",
                "signature": "0x…", "nonce": "…", "deadline": 1893456000,
            })
            # → { request_id, status: "initiated" } … disburses in seconds

            # 2) Quote the debt
            info = await s.call_tool("get_repayment_info",
                                     {"agent_id": "0xYourAgentWallet"})
            # → { request_id, repayment_amount, pay_to }

            # 3) Send the EXACT repayment_amount in USDC to pay_to
            #    (your wallet stack does this - CDP, viem, web3.py, …)

            # 4) Confirm
            await s.call_tool("confirm_repayment", {
                "request_id": "req_…", "tx_hash": "0x…",
            })
            # → { status: "repaid" } + positive ERC-8004 mark

asyncio.run(main())

REST mirror - free reads & x402-paid intelligence

Agents without MCP support can use the same server over plain REST. Reads and repayment are free; underwriting intelligence is paid per request via x402 USDC micropayments - no account, no subscription, your agent pays the 402 challenge and gets the answer.

Free

GET  /api/interest-rates             current protocol rates
GET  /api/creditworthiness/{agent}   score + history for any agent
GET  /api/repay-info/{agent}         amount owed + treasury address
POST /api/repay                      report a repayment tx (money in is always free)
GET  /api/agents/{id|wallet}         ERC-8004 directory entry (see Agent Directory)
GET  /api/agents/recent              recently registered agents (bounded scan)
GET  /api/agents/search?q=           search the same bounded window

Paid (x402, USDC on Base)

GET  /paid/interest-rates        $0.001   rates snapshot
GET  /paid/reputation/{agent}    $0.001   ERC-8004 ReputationRegistry snapshot
POST /paid/credit-check          $0.01    Bank Analyst (Kelly-AMM) assessment
POST /paid/risk-score            $0.05    Gatekeeper + Analyst + Treasury caps
POST /paid/kya-verify            $0.10    signed JWT KYA token (verifiable offline)
POST /paid/validation-attest     $1.00    bank-signed ERC-8004 validation attestation
POST /paid/loans                 $0.01    loan request (same signature contract)

A2A Protocol - the bank as a peer agent

The bank also speaks the A2A protocol (v1.0) - the Linux Foundation standard for agent-to-agent delegation. Any A2A client can discover the bank through its Agent Card and delegate banking tasks: preview terms, request a loan, check status, confirm repayment. Same underwriting, same EIP-712 signature contract as REST and MCP - the A2A surface transports your signature, it never signs for you.

Agent Card (discovery)

https://nng7khybjb4wlwe64r3eagbxhm0ihurx.lambda-url.us-east-1.on.aws/.well-known/agent-card.json

8 skills advertised: get_interest_rates, get_creditworthiness, get_reputation, negotiate_loan, get_loan_status, request_loan, get_repayment_info, confirm_repayment.

Delegate a task (JSON-RPC)

Send a SendMessage request with a data part shaped {"skill": <name>, ...params}. The A2A-Version: 1.0 header is required.

POST https://nng7khybjb4wlwe64r3eagbxhm0ihurx.lambda-url.us-east-1.on.aws/
Content-Type: application/json
A2A-Version: 1.0

{
  "jsonrpc": "2.0", "id": 1, "method": "SendMessage",
  "params": { "message": { "role": "ROLE_USER", "parts": [
    { "data": { "skill": "negotiate_loan", "agent_id": "0xYourWallet", "amount": 10 } }
  ]}}
}

negotiate_loan previews terms (credit analysis, no disbursement); sign the proposed terms and call request_loan to execute. Money-moving skills require the borrower's EIP-712 signature exactly like the Quickstart.

AgentKit Provider - the bank in your agent's toolbox

Building with Coinbase AgentKit? One package gives your agent the full credit cycle: rates, credit history, AgentTrust-8004 trust scores and real USDC loans on Base - signing the bank's EIP-712 LoanRequest natively with the agent's own wallet provider. The bank never sees a private key.

npm install rsoft-bank-agentkit
import { AgentKit } from "@coinbase/agentkit";
import { rsoftBankActionProvider } from "rsoft-bank-agentkit";

const agentKit = await AgentKit.from({
  walletProvider, // any EVM wallet provider on Base mainnet
  actionProviders: [
    rsoftBankActionProvider({
      apiKey: process.env.RSOFT_BANK_API_KEY, // loans; reads are free
    }),
  ],
});

6 actions: get_interest_rates, get_creditworthiness, get_trust_score, request_loan, get_repayment_info, confirm_repayment. Repay with AgentKit's native erc20 transfer + confirm_repayment. Source: github.com/rsoft-latam/rsoft-bank-agentkit · npm

OpenClaw Skill - the bank as installable commands

Running an OpenClaw agent? The official bank skill packages the whole cycle - check rates and credit, sign the loan request, borrow, and repay - as ready-to-run commands. It signs with a Coinbase CDP wallet (the key never leaves Coinbase's enclave) and reads its config from a file you control, so an agent can switch wallets by pointing at a different file. A live OpenClaw agent has borrowed and repaid a real loan through it, end to end.

Install

# install the official skill (Base mainnet, real USDC)
npx clawhub install rsoft-agentic-bank

# install its dependencies (Coinbase CDP SDK), once
cd <skill-dir> && npm install

# skill page: https://clawhub.ai/rsoft-latam/skills/rsoft-agentic-bank

Configure your CDP wallet

# a file only you can read — keep it OUT of synced folders
mkdir -p ~/.rsoft && cat > ~/.rsoft/wallet.env <<'EOF'
CDP_API_KEY_ID=your-cdp-api-key-id
CDP_API_KEY_SECRET=your-cdp-api-key-secret
CDP_WALLET_SECRET=your-cdp-wallet-secret
AGENT_WALLET=0xYourWalletAddress
BANK_API_KEY=your-pilot-api-key      # for loan origination
EOF
chmod 600 ~/.rsoft/wallet.env
export WALLET_CONFIG_PATH=~/.rsoft/wallet.env

🔒 CDP credentials control every wallet in that CDP project - use a project dedicated to this agent, never one holding funds you don't want it to touch.

Borrow & repay

node bin/address.js            # your wallet address (verifies CDP access)
node bin/request-loan.js 5     # sign + request a 5 USDC loan (one shot)
node bin/repay.js              # quote, pay the exact amount, confirm — one shot

Real USDC on Base mainnet. The bank only originates loans signed by the borrowing wallet - same security contract as every other door into the bank.

Trust API - on-chain trust scoring
Beta

RSoft Trust scores any agent wallet by what its ERC-8004 identity says on Base mainnet - powered by AgentTrust-8004, a model trained on a real census of 54,802 registered agents (published on Hugging Face). The bank itself logs this score inside every signed loan decision record, and the MCP server exposes it as get_trust_score. Free public reads while in beta.

Score a wallet

GET https://7pdor5bjoty7gyat56u6fgcrue0gbvnd.lambda-url.us-east-1.on.aws/score/0xYourWallet

{
  "wallet": "0x6c37...ccda",
  "registered": true,
  "trust_score": 98,          // 0-100, directional: identity age + reputation
  "anomaly": false,           // true = incoherent profile (e.g. reputation farming)
  "reason": "within normal census distribution",
  "features": { "identity_age_days": 201.9, "client_count": 3 }
}

Unregistered wallets score 0 - no ERC-8004 identity means no anchor to score. First read for a wallet walks Base history (~40s); repeats are cached. Beta: model v0 uses the two features readable directly on-chain; richer features land with the event indexer.

RSoft Sentiment (ASI)

Beta

The first trust-weighted sentiment index for AI agents: reads what ERC-8004 agents DO on-chain (positions, capital, reputation) - not what humans say - and weights every agent's vote by its trust score. Anomalous profiles are excluded from the index entirely.

GET https://g3w2egj3mgmjezpzgtnzhkd5h40kqtxd.lambda-url.us-east-1.on.aws/api/v1/sentiment/asi

Trust SDK - policies, gates and pricing

POST /evaluate turns the trust score into a decision: pick a policy (or compose your own gates), get a tier, pass/fail per gate, the anomaly flag and an optional price multiplier for the wallet. Gates come only from real on-chain signals - nothing self-reported. Keyless. Base URL https://7pdor5bjoty7gyat56u6fgcrue0gbvnd.lambda-url.us-east-1.on.aws.

Evaluate a wallet against a policy

POST /evaluate
{ "wallet": "0x…", "policy": "standard", "include_pricing": true, "base_price_usdc": 1.0 }

{
  "wallet": "0x…",
  "registered": true,
  "trust_score": 82,
  "trust_tier": "verified",       // trusted | verified | limited | untrusted | blocked
  "anomaly": false,
  "policy": "standard", "operator": "AND",
  "all_passed": true,
  "gate_results": [
    { "gate": "registered",  "passed": true, "value": true,  "threshold": true },
    { "gate": "established", "passed": true, "value": 201.9, "threshold": 30 },
    ...
  ],
  "pricing": { "price_multiplier": 0.77, "suggested_price_usdc": 0.77,
               "suggested_interest_rate": ...,   // indicative only
               "bank_risk_tier_equivalent": "A", ... }
}

Policies: quick, basic, standard, strict, financial, reputation, or custom {gates, operator: AND|OR|WEIGHTED, weights, threshold}. Gates: registered (ERC-8004 identity), established (identity ≥ 30 days), active (≥ 1 reputation client), coherent (no anomaly), score (≥ 50). Also GET /policies and GET /pricing?wallet=&base_price_usdc=.

Pricing

price_multiplier = 2.0 − 1.5 · trust_score / 100. A trusted wallet pays down to 0.5×, an unknown one 2.0×; anomalous or unregistered wallets are always 2.0×. The suggested_interest_rate is indicative only - the bank prices its own loans with its Kelly/AMM model, not with this number.

SDKs

TypeScript · npm rsoft-trust 0.1.0

npm install rsoft-trust

import { TrustClient } from "rsoft-trust";
const r = await new TrustClient().evaluate({ wallet, policy: "standard" });
if (!r.all_passed) throw new Error(r.trust_tier);

// Express: 403 with the gate breakdown when the policy fails
import { trustGate } from "rsoft-trust/express";
app.post("/pay",
  trustGate({ policy: "standard", walletFrom: (req) => req.headers["x-wallet"] }),
  handler);

// Edge / Workers / Next.js route handlers (WHATWG Request → Response)
import { trustGuard } from "rsoft-trust/fetch";
const g = await trustGuard(req, { policy: "standard" });
if (!g.ok) return g.response;

Python · PyPI rsoft-trust 0.1.0

pip install "rsoft-trust[fastapi]"

from rsoft_trust import TrustClient
async with TrustClient() as trust:
    r = await trust.evaluate(wallet, policy="standard")
    # or: await trust.require(wallet, "standard")  → raises TrustGateError

# FastAPI dependency (wallet from X-Wallet header or ?wallet=)
from rsoft_trust.fastapi import require_trust
@app.post("/pay", dependencies=[Depends(require_trust(policy="standard"))])
async def pay(): ...

Source for both packages: github.com/rsoft-latam/rsoft-trust-api under packages/.

API Reference

Public GET endpoints for querying loan data, workflow status, and protocol information.

Loans

GET
/api/v1/loan/status/{request_id}

Get Loan Status

Retrieve the current status and details of a specific loan request.

Path Parameters

request_idstringThe unique loan request identifier

Response

{
  "request_id": "req_abc123def456",
  "status": "disbursed",
  "agent_wallet": "0x1234...abcd",
  "loan_amount": 1000,
  "amount_approved": 1000,
  "interest_rate": 0.085,
  "term_days": 30,
  "tx_hash": "0xabc...def",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:31:45Z"
}
GET
/api/v1/loan/workflow/{request_id}

Get Workflow Steps

Retrieve the detailed execution status of each agent in the workflow pipeline. Includes timing, results, and errors for every step.

Path Parameters

request_idstringThe unique loan request identifier

Response

{
  "request_id": "req_abc123def456",
  "loan_status": "disbursed",
  "workflow_status": "completed",
  "total_duration_ms": 12450,
  "current_step": null,
  "steps": [
    {
      "step": "gatekeeper",
      "step_order": 1,
      "status": "completed",
      "started_at": "2025-01-15T10:30:00Z",
      "completed_at": "2025-01-15T10:30:02Z",
      "duration_ms": 2100,
      "result": { ... },
      "error": null
    }
  ],
  "created_at": "2025-01-15T10:30:00Z",
  "completed_at": "2025-01-15T10:31:45Z"
}
GET
/api/v1/loan/history/{wallet_address}

Get Agent Loan History

Retrieve the loan history for a specific wallet address. Returns all past and current loan requests.

Path Parameters

wallet_addressstringThe agent's wallet address

Query Parameters

limitintegerMax number of results (default: 10)

Response

[
  {
    "request_id": "req_abc123def456",
    "status": "repaid",
    "agent_wallet": "0x1234...abcd",
    "loan_amount": 1000,
    "amount_approved": 1000,
    "interest_rate": 0.085,
    "term_days": 30,
    "current_node": null,
    "tx_hash": "0xabc...def",
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-20T14:00:00Z"
  }
]
GET
/api/v1/loan/explorer

Loan Explorer

Public paginated endpoint to browse all protocol loans. Supports filtering by status. No authentication required.

Query Parameters

pageintegerPage number (default: 1)
limitintegerItems per page (default: 20)
statusstringFilter by loan status

Response

{
  "loans": [
    {
      "request_id": "req_abc123",
      "agent_wallet": "0x1234...abcd",
      "amount": 1000,
      "currency": "USDC",
      "status": "disbursed",
      "interest_rate": 0.085,
      "duration_days": 30,
      "disbursement_tx_hash": "0xabc...def",
      "created_at": "2025-01-15T10:30:00Z"
    }
  ],
  "total": 42,
  "page": 1,
  "limit": 20,
  "total_pages": 3
}
GET
/api/v1/loan/active/{wallet_address}

Get Active Loans

Retrieve all currently active loans for a wallet address. Includes outstanding balance summary.

Path Parameters

wallet_addressstringThe agent's wallet address

Response

{
  "active_loans": [
    {
      "request_id": "req_abc123def456",
      "amount": 1000,
      "interest_rate": 0.085,
      "duration_days": 30,
      "repayment_amount": 1085,
      "status": "disbursed",
      "disbursement_tx_hash": "0xabc...def",
      "created_at": "2025-01-15T10:30:00Z"
    }
  ],
  "active_loans_count": 1,
  "total_outstanding": 1085,
  "wallet_address": "0x1234...abcd",
  "agent_id": "agent-001"
}

Agents & Rates

GET
/api/v1/agents/{agent_id}/creditworthiness

Check Creditworthiness

Evaluate an agent's creditworthiness based on loan history and risk profile.

Path Parameters

agent_idstringThe unique agent identifier

Response

{
  "agent_id": "agent-001",
  "credit_score": 750,
  "risk_tier": "low"
}
GET
/api/v1/interest-rates

Interest Rates

Retrieve current protocol interest rates. Rates are updated dynamically based on protocol utilization.

Response

{
  "base_rate": 0.05,
  "risk_tiers": {
    "low": { "rate": "..." },
    "medium": { "rate": "..." },
    "high": { "rate": "..." }
  },
  "yield_strategies": {
    "conservative": { "apy": "..." },
    "balanced": { "apy": "..." },
    "aggressive": { "apy": "..." },
    "dynamic": { "apy": "..." }
  },
  "updated_at": "2025-01-15T00:00:00Z"
}
GET
/api/v1/agents/{wallet}/controls

Sponsor Controls

Sponsor binding, sponsor-set controls and the effective borrowing ceiling for an agent. Public. See Sponsor Controls.

Path Parameters

walletstringThe agent's wallet address

Response

{
  "sponsor":  { "bound": true, "kind": "phone", "status": "active" },
  "controls": { "paused": false, "revoked": false, "max_loan_amount": 20,
                "daily_draw_cap": 50, "draft_mode_enabled": true, "version": 3 },
  "effective": { "ladder_limit": 10, "ladder_level": 1, "global_max": 25,
                 "sponsor_cap": 20, "effective_ceiling": 10,
                 "daily_used": 0, "daily_remaining": 50 },
  "pending_draft": null
}

Agent Directory (ERC-8004)

GET
/api/v1/agents/registry/{token_id}

Registry Entry by Token ID

Identity + reputation registry read for one ERC-8004 agent on Base mainnet, plus the bank's own credit standing if the wallet is a customer. Public.

Path Parameters

token_idintegerERC-8004 Identity Registry token id

Response

{
  "token_id": 58492,
  "exists": true,
  "owner": "0x…",
  "agent_wallet": "0x…",
  "canonical_uri": "https://…",
  "client_count": 1,
  "clients": ["0x…"],
  "known_issuers": [ ... ],
  "trusted_feedback_count": 4,
  "trusted_feedback_value": ...,
  "chain_id": 8453,
  "identity_registry": "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  "reputation_registry": "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
  "bank": { ... }
}
GET
/api/v1/agents/registry/by-wallet/{wallet}

Registry Entry by Wallet

Same payload as the token-id lookup, resolved from the agent wallet. Public.

Path Parameters

walletstringThe agent's wallet address

Response

{ "token_id": 58492, "exists": true, "agent_wallet": "0x…", ... }
GET
/api/v1/agents/registry/recent

Recently Registered Agents

Bounded scan of recent Registered events (default 5000 blocks) plus the bank's own customer table. The IdentityRegistry is not enumerable on mainnet, so this is not the full census; the response says what was scanned. Public.

Query Parameters

limitintegerMax number of agents to return

Response

{
  ...,                            // the matched agents (same shape as a registry entry)
  "scanned_window": { ... },      // blocks actually scanned
  "limitation": "…"               // states that the registry is not enumerable
}
GET
/api/v1/agents/registry/search

Search Agents

Search within the same bounded window and the bank's customer table. Same limitation and scanned_window as recent. Public.

Query Parameters

qstring
required
Search term

Response

{
  ...,                            // the matched agents
  "scanned_window": { ... },
  "limitation": "…"
}

Webhooks

All webhook endpoints require X-API-Key. Request shapes, events and the signature scheme are in the Webhooks section.

POST   /api/v1/webhooks                    { url, events[], agent_wallet? } → { id, secret }  (secret shown once)
GET    /api/v1/webhooks?agent_wallet=0x…   list subscriptions
DELETE /api/v1/webhooks/{id}               remove a subscription
POST   /api/v1/webhooks/{id}/ping          send a test delivery
GET    /api/v1/webhooks/{id}/deliveries    delivery attempts and responses

Health Checks

GET
/health

Health Check

Returns the overall health status of the API and its dependencies.

Response

{
  "status": "healthy"
}
GET
/health/ready

Readiness Check

Kubernetes-style readiness probe. Returns 200 when the service is ready to accept traffic.

Response

{
  "status": "ready"
}
GET
/health/live

Liveness Check

Kubernetes-style liveness probe. Returns 200 as long as the service process is running.

Response

{
  "status": "alive"
}

Status Codes & Loan States

Loan Statuses

initiated
Loan request received, workflow starting
approved
Loan approved, awaiting settlement
disbursed
Funds transferred to agent wallet
repaid
Loan fully repaid by agent
rejected
Loan request denied
defaulted
Loan past due, repayment not received
failed
Workflow error or settlement failure
draft_pending_sponsor
Above the effective ceiling; waiting for the sponsor (24h). Not outstanding debt
draft_rejected
Sponsor rejected the draft. Not outstanding debt
draft_expired
No sponsor decision within 24h. Not outstanding debt

HTTP Status Codes

200
OK

Request succeeded

202
Accepted

Loan request parked as a draft pending sponsor approval (draft mode)

400
Bad Request

Invalid parameters or request body

404
Not Found

Resource not found (invalid request_id, wallet, etc.)

500
Server Error

Internal server error

Error Response Format

All error responses follow a consistent format with a detail field describing the error.

{
  "detail": "Loan request not found: req_invalid_id"
}