When working with tokens that use bonding curves (like pump.fun on Solana or clanker on Base), you often need to find the bonding curve contract address to interact with the pool before it migrates to a traditional AMM. This cookbook shows you two methods to retrieve bonding curve addresses using Mobula’s API.
Two Methods to Find Bonding Curves
Method 1: Using token/details (Recommended)
The simplest way - directly get the bondingCurveAddress field:
curl -X GET "https://api.mobula.io/api/2/token/details?address=TOKEN_ADDRESS" \
-H "Authorization: YOUR_API_KEY"
Method 2: Using token/markets
List ALL pools/markets for a token, then find the bonding curve by matching the pool type with the token’s source:
curl -X GET "https://api.mobula.io/api/2/token/markets?address=TOKEN_ADDRESS" \
-H "Authorization: YOUR_API_KEY"
Understanding Bonding Curves
A bonding curve is a pricing mechanism where token price increases as more tokens are purchased. Many protocols use bonding curves to bootstrap liquidity for new tokens before eventually migrating to traditional AMM pools once a threshold is reached.
Key Concepts
source : The protocol that launched the token (e.g., “pumpfun”, “clanker”, “moonshot”)
type : The pool type identifier (e.g., “pumpfun”, “clanker”, “uniswap-v2”)
Bonding Curve Pool : When a token’s source matches a pool’s type, that pool is the bonding curve. For example:
Token source: “pumpfun” → Pool type: “pumpfun” = Bonding curve
Token source: “clanker” → Pool type: “clanker” = Bonding curve
Key Response Fields
Field Type Description sourcestring Protocol that launched the token typestring Pool type identifier bondingCurveAddressstring | null Contract address of the bonding curve pool bondedboolean Whether token completed bonding and migrated bondingPercentagenumber Progress towards bonding completion (0-100%)
Method 1: Using token/details (Simplest)
TypeScript
import { MobulaClient } from '@mobula/sdk' ;
const client = new MobulaClient ({
apiKey: process . env . MOBULA_API_KEY
});
async function getBondingCurveFromDetails (
tokenAddress : string ,
blockchain ?: string
) {
const response = await client . fetchTokenDetails ({
address: tokenAddress ,
blockchain: blockchain
});
const token = response . data ;
return {
bondingCurveAddress: token . bondingCurveAddress ,
bonded: token . bonded ,
bondingPercentage: token . bondingPercentage ,
source: token . source ,
poolAddress: token . poolAddress
};
}
// Example: pump.fun token on Solana
const result = await getBondingCurveFromDetails (
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump' ,
'solana'
);
console . log ( result );
// {
// bondingCurveAddress: "7xKp...abc123",
// bonded: false,
// bondingPercentage: 67.5,
// source: "pumpfun",
// poolAddress: "7xKp...abc123"
// }
Python
import requests
API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.mobula.io/api/2'
def get_bonding_curve_from_details ( token_address : str , blockchain : str = None ) -> dict :
params = { 'address' : token_address}
if blockchain:
params[ 'blockchain' ] = blockchain
response = requests.get(
f ' { BASE_URL } /token/details' ,
params = params,
headers = { 'Authorization' : API_KEY }
)
response.raise_for_status()
token = response.json().get( 'data' , {})
return {
'bonding_curve_address' : token.get( 'bondingCurveAddress' ),
'bonded' : token.get( 'bonded' ),
'bonding_percentage' : token.get( 'bondingPercentage' ),
'source' : token.get( 'source' ),
'pool_address' : token.get( 'poolAddress' )
}
# Example
result = get_bonding_curve_from_details(
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump' ,
'solana'
)
print (result)
Method 2: Using token/markets (Advanced)
This method lists ALL pools and finds the bonding curve by matching pool type with token source.
TypeScript
async function getBondingCurveFromMarkets (
tokenAddress : string ,
blockchain ?: string
) {
const response = await client . fetchTokenMarkets ({
address: tokenAddress ,
blockchain: blockchain ,
limit: 25
});
const markets = response . data ;
if ( markets . length === 0 ) {
return { error: 'No markets found' };
}
// Get token source from any market (all markets have same base token)
const tokenSource = markets [ 0 ]. base . source ;
// Find bonding curve: pool type matches token source
const bondingCurve = markets . find ( m => m . type === tokenSource );
if ( ! bondingCurve ) {
return {
status: 'no-bonding-curve' ,
message: `No bonding curve found (source: ${ tokenSource } )`
};
}
return {
bondingCurveAddress: bondingCurve . address ,
bondingPercentage: bondingCurve . bondingPercentage ,
bonded: bondingCurve . bonded ,
source: tokenSource ,
poolType: bondingCurve . type ,
liquidityUSD: bondingCurve . liquidityUSD ,
exchange: bondingCurve . exchange . name
};
}
// Example: pump.fun token
const result = await getBondingCurveFromMarkets (
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump' ,
'solana'
);
console . log ( result );
// {
// bondingCurveAddress: "7xKp...abc123",
// bondingPercentage: 67.5,
// bonded: false,
// source: "pumpfun",
// poolType: "pumpfun",
// liquidityUSD: 45000.50,
// exchange: "Pump.fun"
// }
Python
def get_bonding_curve_from_markets ( token_address : str , blockchain : str = None ) -> dict :
params = { 'address' : token_address, 'limit' : 25 }
if blockchain:
params[ 'blockchain' ] = blockchain
response = requests.get(
f ' { BASE_URL } /token/markets' ,
params = params,
headers = { 'Authorization' : API_KEY }
)
response.raise_for_status()
markets = response.json().get( 'data' , [])
if not markets:
return { 'error' : 'No markets found' }
# Get token source from first market
token_source = markets[ 0 ][ 'base' ].get( 'source' )
# Find bonding curve: pool type matches token source
bonding_curve = next ((m for m in markets if m.get( 'type' ) == token_source), None )
if not bonding_curve:
return {
'status' : 'no-bonding-curve' ,
'message' : f 'No bonding curve found (source: { token_source } )'
}
return {
'bonding_curve_address' : bonding_curve[ 'address' ],
'bonding_percentage' : bonding_curve.get( 'bondingPercentage' ),
'bonded' : bonding_curve.get( 'bonded' ),
'source' : token_source,
'pool_type' : bonding_curve.get( 'type' ),
'liquidity_usd' : bonding_curve.get( 'liquidityUSD' ),
'exchange' : bonding_curve[ 'exchange' ][ 'name' ]
}
# Example
result = get_bonding_curve_from_markets(
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump' ,
'solana'
)
print (result)
How It Works
Understanding the Matching Logic
When you query token/markets, you get ALL pools for a token:
{
"data" : [
{
"address" : "7xKp...abc123" ,
"type" : "pumpfun" , // Pool type
"bonded" : false ,
"bondingPercentage" : 67.5 ,
"base" : {
"source" : "pumpfun" , // Token source
"address" : "HLwEJQ..." ,
"symbol" : "MYTOKEN"
}
},
{
"address" : "8yBp...def456" ,
"type" : "raydium-v4" , // Different pool type
"bonded" : true ,
"base" : {
"source" : "pumpfun" , // Same token source
"address" : "HLwEJQ..." ,
"symbol" : "MYTOKEN"
}
}
]
}
The bonding curve pool is where type matches source :
Pool 1: type: "pumpfun" = source: "pumpfun" ✅ This is the bonding curve!
Pool 2: type: "raydium-v4" ≠ source: "pumpfun" ❌ This is a migrated pool
Response Structure (token/details)
{
"data" : {
"address" : "HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump" ,
"symbol" : "MYTOKEN" ,
"source" : "pumpfun" ,
"bondingCurveAddress" : "7xKp...abc123" ,
"bonded" : false ,
"bondingPercentage" : 67.5 ,
"poolAddress" : "7xKp...abc123" ,
"priceUSD" : 0.000123
}
}
Response Structure (token/markets)
{
"data" : [
{
"address" : "7xKp...abc123" ,
"type" : "pumpfun" ,
"blockchain" : "Solana" ,
"bonded" : false ,
"bondingPercentage" : 67.5 ,
"exchange" : {
"name" : "Pump.fun"
},
"liquidityUSD" : 45000.50 ,
"volume24hUSD" : 125000.00 ,
"base" : {
"address" : "HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump" ,
"symbol" : "MYTOKEN" ,
"source" : "pumpfun"
}
}
]
}
Protocol-Specific Examples
Pump.fun (Solana)
async function getPumpfunBondingCurve ( mintAddress : string ) {
const response = await client . fetchTokenMarkets ({
address: mintAddress ,
blockchain: 'solana'
});
// Find pool where type matches source "pumpfun"
const pumpfunMarket = response . data . find ( m => m . type === 'pumpfun' );
return pumpfunMarket ? {
bondingCurveAddress: pumpfunMarket . address ,
progress: pumpfunMarket . bondingPercentage ,
bonded: pumpfunMarket . bonded ,
liquiditySOL: pumpfunMarket . liquidityUSD / 150
} : null ;
}
Clanker (Base)
async function getClankerBondingCurve ( tokenAddress : string ) {
const response = await client . fetchTokenMarkets ({
address: tokenAddress ,
blockchain: 'base'
});
// Find pool where type matches source "clanker"
const clankerMarket = response . data . find ( m => m . type === 'clanker' );
return clankerMarket ? {
bondingCurveAddress: clankerMarket . address ,
progress: clankerMarket . bondingPercentage ,
bonded: clankerMarket . bonded
} : null ;
}
Moonshot (Solana)
async function getMoonshotBondingCurve ( mintAddress : string ) {
const response = await client . fetchTokenMarkets ({
address: mintAddress ,
blockchain: 'solana'
});
// Find pool where type matches source "moonshot"
const moonshotMarket = response . data . find ( m => m . type === 'moonshot' );
return moonshotMarket ? {
bondingCurveAddress: moonshotMarket . address ,
progress: moonshotMarket . bondingPercentage ,
bonded: moonshotMarket . bonded
} : null ;
}
Generic Function for Any Protocol
async function getBondingCurveBySource (
tokenAddress : string ,
blockchain ?: string
) {
const response = await client . fetchTokenMarkets ({
address: tokenAddress ,
blockchain: blockchain
});
const markets = response . data ;
if ( markets . length === 0 ) return null ;
// Get token source
const source = markets [ 0 ]. base . source ;
// Find pool matching the source
const bondingCurve = markets . find ( m => m . type === source );
return bondingCurve ? {
bondingCurveAddress: bondingCurve . address ,
source: source ,
poolType: bondingCurve . type ,
bonded: bondingCurve . bonded ,
bondingPercentage: bondingCurve . bondingPercentage ,
exchange: bondingCurve . exchange . name
} : null ;
}
Advanced: Monitor Bonding Progress
async function monitorBondingProgress ( tokenAddress : string , blockchain : string ) {
setInterval ( async () => {
const response = await client . fetchTokenDetails ({
address: tokenAddress ,
blockchain: blockchain
});
const token = response . data ;
if ( token . bonded ) {
console . log ( 'Token has completed bonding!' );
console . log ( `Migrated from ${ token . source } to new pool` );
return ;
}
console . log ( `Source: ${ token . source } ` );
console . log ( `Progress: ${ token . bondingPercentage ?. toFixed ( 2 ) } %` );
console . log ( `Bonding curve: ${ token . bondingCurveAddress } ` );
if ( token . bondingPercentage && token . bondingPercentage > 95 ) {
console . log ( 'Warning: Bonding almost complete!' );
}
}, 10000 );
}
Source to Pool Type Mapping
Common bonding curve protocols and their identifiers:
Protocol Source Value Pool Type Value Chains Pump.fun pumpfunpumpfunSolana Moonshot moonshotmoonshotSolana Clanker clankerclankerBase Flap flapflapBase, BNB Nadfun nadfunnadfunBase Mana manamanaBase Raydium Launchlab raydium-launchlabraydium-launchlabSolana Boop boopboopSolana
Best Practices
Use token/details for simplicity : If you only need the bonding curve address, use token/details which directly returns bondingCurveAddress.
Match source with type : When using token/markets, find the pool where type matches the token’s source - that’s your bonding curve.
Bonding curve addresses become inactive : Once bonded: true, the bonding curve pool is no longer active. Token has migrated to a new pool.
Multiple pools are normal : token/markets returns ALL pools for a token (bonding curve + migrated pools). The bonding curve is just one of them.
Troubleshooting
Issue: No pool matches token source
Problem : No pool where type equals token source
Solutions :
Token may have completed bonding (check bonded: true)
Token may not have originated from a bonding curve
Use token/details to check bondingCurveAddress directly
Verify token address is correct
Example :
// Token source: "pumpfun" but no pool with type: "pumpfun"
// This means token has completed bonding
const markets = response . data ;
const source = markets [ 0 ]. base . source ; // "pumpfun"
const bondingCurve = markets . find ( m => m . type === source ); // null
// Check markets[0].bonded === true
Issue: bondingCurveAddress is null
Problem : token/details returns bondingCurveAddress: null
Solutions :
Token has completed bonding - check bonded: true
Token didn’t launch via bonding curve
Check poolAddress for current active pool
Issue: Multiple pools with same type
Problem : Multiple pools found with matching type
Solution : This is unusual but possible. Choose based on:
Pool with bonded: false (active bonding curve)
Highest liquidityUSD
Most recent createdAt date
Comparison: token/details vs token/markets
Feature token/details token/markets Simplicity ✅ Direct bondingCurveAddress field Requires finding pool where type matches source Data Returned Single token info All pools/markets for token Use Case Quick bonding curve lookup Need all pool details, volumes, liquidity Performance Faster (single token) Slower (lists all pools) Best For Simple bonding curve address lookup Market analysis, comparing pools
Token Details API Get bondingCurveAddress directly
Token Markets API List all pools for a token
Market Details API Detailed info about specific pools
Swap Execution API Execute swaps on bonding curves
Get Started
Create a free Mobula API key and start finding bonding curve addresses today!
Need Help?