Documentation Index
Fetch the complete documentation index at: https://docs.b402.ai/llms.txt
Use this file to discover all available pages before exploring further.
POST /wallet/settle takes the signed UserOperation from /wallet/verify and submits it to the ERC-4337 bundler for on-chain execution. The facilitator polls for the receipt and returns the transaction hash with payment details.
Base URL
https://facilitatorv3.b402.ai
Request
curl -X POST https://facilitatorv3.b402.ai/wallet/settle \
-H "Content-Type: application/json" \
-d '{
"userOp": {
"sender": "0x...wallet_address",
"nonce": "0x...",
"callData": "0x...encoded_batch_call",
"callGasLimit": "0x...",
"verificationGasLimit": "0x...",
"preVerificationGas": "0x...",
"maxFeePerGas": "0x...",
"maxPriorityFeePerGas": "0x...",
"paymaster": "0x...",
"paymasterVerificationGasLimit": "0x...",
"paymasterPostOpGasLimit": "0x...",
"paymasterData": "0x...",
"signature": "0x...user_signature_of_userOpHash"
},
"signature": "0x...user_signature_of_userOpHash"
}'
import { Wallet } from 'ethers';
// 1. Get unsigned UserOp from /wallet/verify
const verifyRes = await fetch('https://facilitatorv3.b402.ai/wallet/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
walletAddress: '0x...nexus_smart_wallet',
transactions: [
{
to: '0x...recipient',
amount: '10000000000000000',
token: '0x55d398326f99059fF775485246999027B3197955',
},
],
paymentRequirements: { network: 'bsc' }, // or 'base'
}),
});
const { userOp, userOpHash } = await verifyRes.json();
// 2. Sign the userOpHash with the wallet owner's key
const ownerWallet = new Wallet(process.env.PRIVATE_KEY);
const signature = await ownerWallet.signMessage(
Buffer.from(userOpHash.slice(2), 'hex')
);
// 3. Submit signed UserOp to /wallet/settle
const settleRes = await fetch('https://facilitatorv3.b402.ai/wallet/settle', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userOp: { ...userOp, signature },
signature,
}),
});
const result = await settleRes.json();
console.log('TX:', result.txHash);
Request Body
| Field | Type | Required | Description |
|---|
userOp | object | Yes | The full UserOperation object returned by /wallet/verify, with the signature field populated |
userOp.signature | string | Yes | User’s signature of the userOpHash (hex) |
signature | string | Yes | Same user signature, provided at the top level for validation |
The userOp object must contain all fields exactly as returned by /wallet/verify. Do not modify any field other than signature.
Response
200 - Settlement Successful
{
"success": true,
"txHash": "0x...",
"userOpHash": "0x...",
"payments": [
{
"to": "0x...recipient",
"amount": "10000000000000000",
"token": "0x...token"
}
]
}
Response Fields
| Field | Type | Description |
|---|
success | boolean | Whether the transaction was mined successfully |
txHash | string | On-chain transaction hash (use on BscScan or b402scan to inspect) |
userOpHash | string | UserOperation hash matching the one from /wallet/verify |
payments | array | Parsed payment events extracted from transaction logs |
payments[].to | string | Recipient address |
payments[].amount | string | Amount transferred in token wei |
payments[].token | string | ERC-20 token contract address |
Error Responses
| Status | Code | Description |
|---|
| 400 | validation_error | Missing or malformed userOp or signature |
| 400 | validation_error | Signature does not match the userOpHash |
| 400 | userop_error | Bundler rejected the UserOp (insufficient gas, nonce conflict, paymaster denial) |
| 500 | blockchain_error | Transaction reverted or receipt polling timed out |
What Happens Server-Side
- Injects signature - Places the user’s signature into the UserOp
- Submits to bundler - Sends the signed UserOp to the ERC-4337 bundler via
eth_sendUserOperation
- Polls for receipt - Waits for the bundler to mine the transaction and return a receipt
- Extracts payment events - Parses
Transfer events from the transaction logs to build the payments array
- Returns result - Responds with the transaction hash and payment breakdown
Error Handling
Bundler-level failures return userop_error. Common causes:
| Cause | What To Do |
|---|
| Nonce already used | Re-call /wallet/verify to get a fresh UserOp |
| Paymaster expired | Re-call /wallet/verify for new paymaster data |
| Insufficient balance | Token balance changed between verify and settle |
| Gas estimation mismatch | Network conditions changed; retry from verify |
For all userop_error and blockchain_error responses, the safe recovery path is to re-call /wallet/verify and restart the flow.
Full Flow
Client Facilitator Bundler / Chain
| | |
| POST /wallet/verify | |
| { walletAddress, transactions } | |
|--------------------------------->| |
| |-- validate wallet, balance |
| |-- build callData + fee |
| |-- estimate gas via bundler --->|
| |<--- gas estimates -------------|
| |-- sign paymaster data |
| { userOp, userOpHash } | |
|<---------------------------------| |
| | |
| sign(userOpHash) | |
| | |
| POST /wallet/settle | |
| { userOp + signature } | |
|--------------------------------->| |
| |-- eth_sendUserOperation ------>|
| |-- poll for receipt ----------->|
| |<--- receipt + logs ------------|
| { txHash, payments } | |
|<---------------------------------| |