Retrieve ERC-20 token approval (allowance) records for a wallet on a specific chain. Each approval represents a transaction where the wallet granted a spender contract permission to transfer tokens on its behalf.
Cost: 1 credit per call (WALLET credits)
Endpoint
GET https://api.octav.fi/v1/approvals/:chain
Path Parameters
Chain identifier Supported chains: arbitrum, avalanche, base, binance, ethereum, fantom, gnosis, linea, optimism, polygon See Supported Blockchains for details
Required Parameters
Wallet address to fetch approvals for addresses=0x6426af179aabebe47666f345d69fd9079673f6cd
Optional Parameters
Number of results per page
Minimum: 1
Maximum: 100
Default: 25
Cursor string from a previous response to fetch the next page cursor=eyJhbGciOiJIUzI1NiJ9...
Response
Top-Level Fields
Cursor for the next page. null or absent when there are no more results.
Number of items returned in this page.
Array of token approval records.
Approval Object
Each item in items contains:
Block number where the approval transaction was mined.
ISO 8601 timestamp of the block.
Transaction hash of the approval.
Address of the token contract that was approved.
Wallet address that granted the approval.
Spender address that received the approval.
Raw approved amount (not decimal-adjusted). A max uint256 value indicates unlimited approval.
Enriched token metadata. Present only when the token is tracked in the Octav asset database. Contains: name, symbol, balance, price, value, decimal, chain, contract, imgSmall, imgLarge Follows the standard AssetViewModel shape used across other Octav API responses.
Example Request
cURL
JavaScript
Python
TypeScript
curl -X GET "https://api.octav.fi/v1/approvals/ethereum?addresses=0x6426af179aabebe47666f345d69fd9079673f6cd&limit=25" \
-H "Authorization: Bearer YOUR_API_KEY"
Example Response
{
"cursor" : "eyJhbGciOiJIUzI1NiJ9..." ,
"pageSize" : 25 ,
"items" : [
{
"block" : "19432156" ,
"timestamp" : "2024-03-15T10:23:47.000Z" ,
"hash" : "0xa1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2" ,
"contract" : "0x6b175474e89094c44da98b954eedeac495271d0f" ,
"from" : "0x6426af179aabebe47666f345d69fd9079673f6cd" ,
"to" : "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" ,
"amount" : "115792089237316195423570985008687907853269984665640564039457584007913129639935" ,
"asset" : {
"name" : "Dai Stablecoin" ,
"symbol" : "DAI" ,
"balance" : "1500.25" ,
"price" : "0.9998" ,
"value" : "1499.95" ,
"decimal" : "18" ,
"chain" : "ethereum" ,
"contract" : "0x6b175474e89094c44da98b954eedeac495271d0f" ,
"imgSmall" : "https://assets.coingecko.com/coins/images/9956/small/dai-multi-collateral-mcd.png" ,
"imgLarge" : "https://assets.coingecko.com/coins/images/9956/large/dai-multi-collateral-mcd.png"
}
},
{
"block" : "19215432" ,
"timestamp" : "2024-02-10T14:05:22.000Z" ,
"hash" : "0xf9e8d7c6b5a4f9e8d7c6b5a4f9e8d7c6b5a4f9e8d7c6b5a4f9e8d7c6b5a4f9e8" ,
"contract" : "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" ,
"from" : "0x6426af179aabebe47666f345d69fd9079673f6cd" ,
"to" : "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" ,
"amount" : "50000000000" ,
"asset" : {
"name" : "USD Coin" ,
"symbol" : "USDC" ,
"balance" : "10234.50" ,
"price" : "1.0001" ,
"value" : "10235.52" ,
"decimal" : "6" ,
"chain" : "ethereum" ,
"contract" : "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" ,
"imgSmall" : "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png" ,
"imgLarge" : "https://assets.coingecko.com/coins/images/6319/large/USD_Coin_icon.png"
}
}
]
}
Use cursor-based pagination to iterate through results:
Make an initial request with just limit (or use the default of 25)
If the response contains a non-null cursor, pass it as the cursor query parameter in the next request
When cursor is null or absent, you have reached the end of the results
async function getAllApprovals ( chain , address ) {
const approvals = [];
let cursor = null ;
do {
const params = new URLSearchParams ({
addresses: address ,
limit: '100'
});
if ( cursor ) params . set ( 'cursor' , cursor );
const response = await fetch (
`https://api.octav.fi/v1/approvals/ ${ chain } ? ${ params } ` ,
{
headers: {
'Authorization' : `Bearer ${ apiKey } `
}
}
);
const data = await response . json ();
approvals . push ( ... data . items );
cursor = data . cursor ;
} while ( cursor );
return approvals ;
}
Use Cases
Audit Approvals
Multi-Chain Overview
Track Approval Value
Spender Analysis
Review all active token approvals for security: const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935' ;
async function auditApprovals ( chain , address ) {
const approvals = await getAllApprovals ( chain , address );
const unlimited = approvals . filter ( a => a . amount === MAX_UINT256 );
const limited = approvals . filter ( a => a . amount !== MAX_UINT256 );
console . log ( `Total approvals: ${ approvals . length } ` );
console . log ( `Unlimited approvals: ${ unlimited . length } ` );
console . log ( `Limited approvals: ${ limited . length } ` );
// Flag unlimited approvals for review
unlimited . forEach ( approval => {
console . log (
`UNLIMITED: ${ approval . asset ?. symbol || approval . contract } -> ${ approval . to } `
);
});
return { unlimited , limited };
}
Scan approvals across all supported chains: const CHAINS = [
'arbitrum' , 'avalanche' , 'base' , 'binance' ,
'ethereum' , 'fantom' , 'gnosis' , 'linea' ,
'optimism' , 'polygon'
];
async function getMultiChainApprovals ( address ) {
const results = {};
for ( const chain of CHAINS ) {
const approvals = await getAllApprovals ( chain , address );
if ( approvals . length > 0 ) {
results [ chain ] = approvals ;
console . log ( ` ${ chain } : ${ approvals . length } approvals` );
}
}
return results ;
}
Calculate the total value of tokens with active approvals: async function calculateApprovalExposure ( chain , address ) {
const approvals = await getAllApprovals ( chain , address );
let totalExposure = 0 ;
approvals . forEach ( approval => {
if ( approval . asset ) {
totalExposure += parseFloat ( approval . asset . value );
console . log (
` ${ approval . asset . symbol } : $ ${ approval . asset . value } approved to ${ approval . to } `
);
}
});
console . log ( `Total exposure: $ ${ totalExposure . toFixed ( 2 ) } ` );
return totalExposure ;
}
Group approvals by spender contract: async function analyzeSpenders ( chain , address ) {
const approvals = await getAllApprovals ( chain , address );
const spenders = {};
approvals . forEach ( approval => {
if ( ! spenders [ approval . to ]) {
spenders [ approval . to ] = [];
}
spenders [ approval . to ]. push ( approval );
});
// Display spender summary
Object . entries ( spenders )
. sort (( a , b ) => b [ 1 ]. length - a [ 1 ]. length )
. forEach (([ spender , apps ]) => {
const tokens = apps
. map ( a => a . asset ?. symbol || 'Unknown' )
. join ( ', ' );
console . log ( ` ${ spender } : ${ apps . length } tokens ( ${ tokens } )` );
});
return spenders ;
}
Error Responses
Invalid parameters provided. {
"message" : "chain must be one of: arbitrum, avalanche, base, binance, ethereum, fantom, gnosis, linea, optimism, polygon"
}
Common causes:
Invalid or unsupported chain in URL path
Missing addresses query parameter
limit out of range (must be 1-100)
Authentication failed. {
"error" : "Unauthorized" ,
"message" : "Invalid API key"
}
Solution: Check your API key in the Authorization header
Insufficient credits. {
"error" : "Insufficient credits" ,
"message" : "Please purchase more credits to continue"
}
Solution: Purchase more credits at data.octav.fi
Upstream data provider is unavailable. {
"message" : "Failed to fetch token approvals from upstream provider"
}
Solution: Retry after a short delay. If the issue persists, the upstream provider may be experiencing an outage.