Skip to main content

Token Approvals & Allowances

Monitor token approvals and allowances to protect your wallet from malicious contracts.

Try it Live

Open in Swagger UI โ†’ to test these endpoints interactively.

Endpointsโ€‹

EndpointDescriptionPrice
GET /api/approvals/{address}Active approvals$0.02
GET /api/allowances/{address}Token allowances$0.01

GET /api/approvals/{address}โ€‹

Get all active token approvals for a wallet address.

Requestโ€‹

curl "https://api.web3identity.com/api/approvals/0xYourAddress?chain=ethereum"

Query Parametersโ€‹

ParameterTypeDefaultDescription
chainstringethereumChain: ethereum, polygon, arbitrum, optimism, base, bsc
includeNFTsbooleantrueInclude NFT approvals
includeRevokedbooleanfalseInclude revoked approvals

Responseโ€‹

{
"address": "0xYourAddress",
"chain": "ethereum",
"totalApprovals": 23,
"riskScore": 45,
"risk": "MEDIUM",
"approvals": [
{
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"type": "ERC20"
},
"spender": {
"address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"name": "Uniswap Universal Router",
"verified": true,
"protocol": "Uniswap V3"
},
"allowance": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"allowanceFormatted": "unlimited",
"approvedAt": {
"block": 18901234,
"timestamp": "2024-11-15T10:30:00Z",
"transaction": "0xabc..."
},
"lastUsed": {
"block": 19123456,
"timestamp": "2025-01-20T15:45:00Z"
},
"risk": {
"level": "LOW",
"score": 15,
"reasons": ["Verified protocol", "Active usage"]
},
"recommendations": {
"action": "monitor",
"reason": "Active, verified protocol"
}
},
{
"token": {
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"name": "Tether USD",
"symbol": "USDT",
"decimals": 6,
"type": "ERC20"
},
"spender": {
"address": "0x1234567890123456789012345678901234567890",
"name": "Unknown Contract",
"verified": false,
"protocol": null
},
"allowance": "10000000000",
"allowanceFormatted": "10000 USDT",
"approvedAt": {
"block": 17890123,
"timestamp": "2024-03-10T08:15:00Z",
"transaction": "0xdef..."
},
"lastUsed": null,
"risk": {
"level": "HIGH",
"score": 75,
"reasons": [
"Unverified contract",
"Never used",
"6+ months old"
]
},
"recommendations": {
"action": "revoke",
"reason": "Unverified contract with no usage",
"urgency": "high"
}
},
{
"token": {
"address": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
"name": "Bored Ape Yacht Club",
"symbol": "BAYC",
"type": "ERC721"
},
"spender": {
"address": "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC",
"name": "Seaport 1.5",
"verified": true,
"protocol": "OpenSea"
},
"approvalType": "setApprovalForAll",
"approved": true,
"approvedAt": {
"block": 18567890,
"timestamp": "2024-09-05T12:00:00Z",
"transaction": "0xghi..."
},
"risk": {
"level": "MEDIUM",
"score": 40,
"reasons": [
"NFT full approval",
"Verified marketplace"
]
},
"recommendations": {
"action": "review",
"reason": "Consider revoking when not actively trading"
}
}
],
"summary": {
"byRisk": {
"LOW": 8,
"MEDIUM": 10,
"HIGH": 4,
"CRITICAL": 1
},
"byType": {
"ERC20": 18,
"ERC721": 3,
"ERC1155": 2
},
"recommendations": {
"revoke": 5,
"review": 8,
"monitor": 10
}
}
}

GET /api/allowances/{address}โ€‹

Get specific token allowances for spenders.

Requestโ€‹

curl "https://api.web3identity.com/api/allowances/0xYourAddress?chain=ethereum&token=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"

Query Parametersโ€‹

ParameterTypeDefaultDescription
chainstringethereumChain name
tokenstring-Filter by token address
spenderstring-Filter by spender address

Responseโ€‹

{
"address": "0xYourAddress",
"chain": "ethereum",
"token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6
},
"balance": "5000000000",
"balanceFormatted": "5000 USDC",
"allowances": [
{
"spender": {
"address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"name": "Uniswap Universal Router",
"verified": true
},
"allowance": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"allowanceFormatted": "unlimited",
"percentOfBalance": "unlimited",
"canSpend": "all"
},
{
"spender": {
"address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
"name": "Uniswap V2 Router",
"verified": true
},
"allowance": "1000000000",
"allowanceFormatted": "1000 USDC",
"percentOfBalance": "20%",
"canSpend": "1000 USDC"
}
],
"totalAllowance": "unlimited"
}

Risk Levelsโ€‹

RiskScoreCriteriaAction
LOW0-30Verified protocol, active usageMonitor
MEDIUM31-60Known protocol, infrequent useReview
HIGH61-80Unverified, old, or unusedRevoke
CRITICAL81-100Malicious contract, exploitedRevoke immediately

Risk Factorsโ€‹

FactorWeightDescription
Unverified contract+40Contract not verified on block explorer
Unlimited allowance+20Approval for max uint256
Never used+25Approval granted but never utilized
Old approval (>6mo)+15Stale approval
Protocol exploit history+50Protocol has been exploited before
NFT setApprovalForAll+15Full NFT collection approval

SDK Examplesโ€‹

JavaScriptโ€‹

import { Web3IdentityClient } from '@web3identity/sdk';

const client = new Web3IdentityClient();

// Get all approvals
const approvals = await client.getApprovals(
'0xYourAddress',
{ chain: 'ethereum', includeNFTs: true }
);

console.log(`Total Approvals: ${approvals.totalApprovals}`);
console.log(`Risk Score: ${approvals.riskScore}/100 (${approvals.risk})`);

// High-risk approvals
const highRisk = approvals.approvals.filter(
a => a.risk.level === 'HIGH' || a.risk.level === 'CRITICAL'
);

if (highRisk.length > 0) {
console.log(`\nโš ๏ธ ${highRisk.length} high-risk approvals found:`);
highRisk.forEach(approval => {
console.log(` ${approval.token.symbol} โ†’ ${approval.spender.name || approval.spender.address}`);
console.log(` Risk: ${approval.risk.level} (${approval.risk.score})`);
console.log(` Reasons: ${approval.risk.reasons.join(', ')}`);
console.log(` Action: ${approval.recommendations.action.toUpperCase()}`);
});
}

// Unlimited approvals
const unlimited = approvals.approvals.filter(
a => a.allowanceFormatted === 'unlimited'
);
console.log(`\n๐Ÿ“Š Unlimited approvals: ${unlimited.length}`);

// Get specific token allowances
const usdcAllowances = await client.getAllowances(
'0xYourAddress',
{
chain: 'ethereum',
token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
}
);

console.log(`\nUSDC Allowances:`);
console.log(`Balance: ${usdcAllowances.balanceFormatted}`);
usdcAllowances.allowances.forEach(a => {
console.log(` ${a.spender.name}: ${a.allowanceFormatted}`);
});

// Generate revoke transactions (pseudo-code)
const toRevoke = approvals.approvals.filter(
a => a.recommendations.action === 'revoke'
);

console.log(`\n๐Ÿ”ด Recommended revocations: ${toRevoke.length}`);
toRevoke.forEach(approval => {
console.log(` ${approval.token.symbol} โ†’ ${approval.spender.address}`);
// In practice, would generate revoke transaction
});

Pythonโ€‹

from web3identity import Client

client = Client()

# Get all approvals
approvals = client.get_approvals(
'0xYourAddress',
chain='ethereum',
include_nfts=True
)

print(f"Total Approvals: {approvals['totalApprovals']}")
print(f"Risk Score: {approvals['riskScore']}/100 ({approvals['risk']})")

# Analyze by risk level
print("\n๐Ÿ“Š Approvals by Risk Level:")
for risk_level, count in approvals['summary']['byRisk'].items():
print(f" {risk_level}: {count}")

# Find revoke candidates
revoke_list = [
a for a in approvals['approvals']
if a['recommendations']['action'] == 'revoke'
]

print(f"\n๐Ÿ”ด Approvals to revoke: {len(revoke_list)}")
for approval in revoke_list:
token = approval['token']['symbol']
spender = approval['spender'].get('name') or approval['spender']['address'][:10]
print(f" {token} โ†’ {spender}")
print(f" Reasons: {', '.join(approval['risk']['reasons'])}")

# Check specific token
def check_token_exposure(address, token_address, chain='ethereum'):
allowances = client.get_allowances(
address,
chain=chain,
token=token_address
)

total_exposure = 0
unlimited = False

for allowance in allowances['allowances']:
if allowance['allowanceFormatted'] == 'unlimited':
unlimited = True
break
total_exposure += float(allowance['allowance'])

return {
'token': allowances['token']['symbol'],
'balance': allowances['balanceFormatted'],
'spenders': len(allowances['allowances']),
'unlimited': unlimited,
'total_exposure': 'unlimited' if unlimited else total_exposure
}

usdc_exposure = check_token_exposure(
'0xYourAddress',
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
)
print(f"\nUSDC Exposure: {usdc_exposure}")

# NFT approval audit
nft_approvals = [
a for a in approvals['approvals']
if a['token']['type'] in ['ERC721', 'ERC1155']
]

print(f"\n๐Ÿ–ผ๏ธ NFT Approvals: {len(nft_approvals)}")
for nft in nft_approvals:
print(f" {nft['token']['name']} โ†’ {nft['spender'].get('name', 'Unknown')}")
if nft.get('approvalType') == 'setApprovalForAll':
print(f" โš ๏ธ Full collection approved")

cURL Examplesโ€‹

# Get all approvals
curl "https://api.web3identity.com/api/approvals/0xYourAddress?chain=ethereum"

# Include NFT approvals
curl "https://api.web3identity.com/api/approvals/0xYourAddress?chain=ethereum&includeNFTs=true"

# Get approvals on Polygon
curl "https://api.web3identity.com/api/approvals/0xYourAddress?chain=polygon"

# Get USDC allowances
curl "https://api.web3identity.com/api/allowances/0xYourAddress?chain=ethereum&token=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"

# Check specific spender
curl "https://api.web3identity.com/api/allowances/0xYourAddress?chain=ethereum&spender=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"

Rate Limitsโ€‹

TierRate LimitNotes
Free100 requests/dayNo payment required
PaidUnlimited$0.01-$0.02 per call via x402

Common Use Casesโ€‹

Approval Security Auditโ€‹

// Complete security audit of wallet approvals
async function auditApprovals(address, chains = ['ethereum', 'polygon', 'arbitrum']) {
const audits = await Promise.all(
chains.map(chain =>
client.getApprovals(address, { chain, includeNFTs: true })
)
);

const combined = {
totalApprovals: audits.reduce((sum, a) => sum + a.totalApprovals, 0),
highRisk: audits.flatMap(a =>
a.approvals.filter(ap => ap.risk.level === 'HIGH' || ap.risk.level === 'CRITICAL')
),
unlimited: audits.flatMap(a =>
a.approvals.filter(ap => ap.allowanceFormatted === 'unlimited')
),
nftApprovals: audits.flatMap(a =>
a.approvals.filter(ap => ap.token.type === 'ERC721' || ap.token.type === 'ERC1155')
)
};

return combined;
}

const audit = await auditApprovals('0xYourAddress');
console.log(`Total approvals across chains: ${audit.totalApprovals}`);
console.log(`High-risk approvals: ${audit.highRisk.length}`);
console.log(`Unlimited approvals: ${audit.unlimited.length}`);
console.log(`NFT approvals: ${audit.nftApprovals.length}`);

Auto-Revoke Stale Approvalsโ€‹

// Identify stale approvals for revocation
async function findStaleApprovals(address, chain = 'ethereum', maxAgeDays = 180) {
const approvals = await client.getApprovals(address, { chain });

const now = Date.now();
const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;

const stale = approvals.approvals.filter(a => {
const approvedDate = new Date(a.approvedAt.timestamp).getTime();
const age = now - approvedDate;
const neverUsed = !a.lastUsed;

return age > maxAgeMs && neverUsed;
});

return stale.map(a => ({
token: a.token.symbol,
spender: a.spender.name || a.spender.address,
age: Math.floor((now - new Date(a.approvedAt.timestamp).getTime()) / (24 * 60 * 60 * 1000)),
risk: a.risk.level
}));
}

const stale = await findStaleApprovals('0xYourAddress', 'ethereum', 180);
console.log(`Stale approvals (180+ days, never used): ${stale.length}`);

Approval Monitoring Dashboardโ€‹

// Real-time approval monitoring
async function monitorApprovals(address, chains) {
const results = [];

for (const chain of chains) {
const approvals = await client.getApprovals(address, { chain });

results.push({
chain,
totalApprovals: approvals.totalApprovals,
riskScore: approvals.riskScore,
criticalCount: approvals.summary.byRisk.CRITICAL || 0,
highCount: approvals.summary.byRisk.HIGH || 0,
revokeRecommended: approvals.summary.recommendations.revoke
});
}

return results;
}

const dashboard = await monitorApprovals('0xYourAddress', ['ethereum', 'polygon', 'arbitrum']);
console.table(dashboard);