Infrastructure
OnFRA for lenders
OnFRA is financial-reputation infrastructure on Celo — not a consumer app. Lenders call the API to screen borrower wallets before extending credit. Onfra is the reference UI; your integration uses OnFRA directly.
What lenders already look at
On Celo, underwriting today is mostly onchain collateral and basic wallet signals:
- · Collateral value and loan-to-value (Morpho, Aave)
- · USDT / cUSD balance and liquidity
- · KYC and identity (where required)
- · Wallet age and transaction count (manual or ad hoc)
What's missing for MiniPay and stablecoin earners: proof of income. Bank statements don't reflect onchain earnings. That gap is what OnFRA fills.
What OnFRA adds
Onchain income stability
Recurring stablecoin inflows, weekly consistency %, monthly income estimate — from transaction history, not self-reported PDFs.
Wallet reputation score
Maturity, protocol trust, activity consistency — a 0–100 signal lenders can threshold in their own rules.
Loan capacity range
Suggested min/max USD borrowing capacity with confidence level, derived from income + risk + savings discipline.
Trustworthiness & capacity
One API call returns lender-friendly underwriting data: trustworthiness, reputation, average monthly income, and loan capacity range (with confidence).
Onchain passport verification
Borrowers can publish a verified REP-{id} attestation. You verify via API or the OnchainReporter contract.
x402 micropayments
0.01 USDT per screen on Celo — no subscriptions, no API keys. Pay per borrower check from your lender wallet.
Integration flow
- 1. Borrower applies with their Celo wallet address
- 2. Your backend calls
POST /api/lender/screenwith x402 payment from your lender treasury wallet - 3. OnFRA returns
trust.isTrustworthyplus reputation, average monthly income, and loan capacity range - 4. Optional: require borrower to submit a verified passport — verify free via
GET /api/agent/verify/REP-… - 5. Combine OnFRA signal with your collateral and KYC rules — OnFRA does not replace collateral checks
API reference
| Endpoint | Purpose | Cost |
|---|---|---|
| POST /api/lender/screen | Trustworthiness + income + loan capacity for a borrower wallet | 0.01 USDT |
| POST /api/agent/analyze | Full analysis or subset via fields | 0.01 USDT |
| GET /api/wallet/{address}/signals/{signal} | Single signal from cache (free after analyze) | Free |
| GET /api/agent/verify/{id} | Verify borrower passport onchain | Free |
| POST /api/agent/report | Generate verified passport for borrower | 0.10 USDT |
Screen a borrower wallet
curl -X POST https://wallet-profile-orpin.vercel.app/api/lender/screen \
-H "Content-Type: application/json" \
-H "X-PAYMENT: <x402-signature>" \
-d '{
"walletAddress": "0xBorrowerWallet...",
"callerAddress": "0xYourLenderWallet..."
}'Schema: lenderScreenRequest · lenderScreenResult
Verify a borrower passport
curl https://wallet-profile-orpin.vercel.app/api/agent/verify/REP-X141GYYEUM
OnchainReporter: 0x50a8Fc322497e2EAc5489A64ce162E07Fb85E6AB
x402 payment — backend signing
Paid endpoints require an EIP-3009 transferWithAuthorization signature in the X-PAYMENT header. Settlement is handled by the Celo x402 facilitator — no gas required from your side.
- · Set
AGENT_PRIVATE_KEYto a Celo wallet funded with USDC or USDT - · USDC domain:
name: "USDC", version: "2" - · USDT domain:
name: "Tether USD", version: "1"
import { privateKeyToAccount } from 'viem/accounts';
import { createWalletClient, http, toHex, parseUnits, keccak256 } from 'viem';
import { celo } from 'viem/chains';
// Config
const USDC = '0xcebA9300f2b948710d2653dD7B07f33A8B32118C'; // Celo mainnet USDC
const ONFRA_API = 'https://wallet-profile-orpin.vercel.app';
const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY);
const client = createWalletClient({ chain: celo, transport: http(), account });
// 1. Discover the recipient treasury address
const { publicPayTo } = await fetch(`${ONFRA_API}/api/x402/config`).then(r => r.json());
// 2. Sign EIP-3009 transferWithAuthorization
const nonce = keccak256(toHex(Date.now()));
const validBefore = BigInt(Math.floor(Date.now() / 1000) + 300); // 5 min
const value = parseUnits('0.01', 6); // 0.01 USDC
const signature = await client.signTypedData({
domain: { name: 'USDC', version: '2', chainId: 42220, verifyingContract: USDC },
types: {
TransferWithAuthorization: [
{ name: 'from', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'validAfter', type: 'uint256' },
{ name: 'validBefore', type: 'uint256' },
{ name: 'nonce', type: 'bytes32' },
],
},
primaryType: 'TransferWithAuthorization',
message: { from: account.address, to: publicPayTo, value,
validAfter: 0n, validBefore, nonce },
});
// 3. Attach signature and call OnFRA
const payment = JSON.stringify({
from: account.address, to: publicPayTo,
value: value.toString(), validAfter: '0',
validBefore: validBefore.toString(), nonce, signature, token: USDC,
});
const res = await fetch(`${ONFRA_API}/api/lender/screen`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-PAYMENT': payment },
body: JSON.stringify({ walletAddress: '0xBorrower...', callerAddress: account.address }),
});
const { trust, reputationScore, loanCapacity } = await res.json();
// trust.isTrustworthy → boolean
// reputationScore → 0-100
// loanCapacity → { min, max, currency, confidence }Discovery & agent protocols
Pilot with us
We're looking for Celo lenders and MFIs to run a 5–10 borrower pilot: screen wallets via API, optionally require REP- passports, measure time-to-underwrite vs. your current flow.
Contact @onfra_xyzOnfra is the borrower-facing reference app. Back to Onfra