Skip to main content
Many traders need to retrieve the full list of available perpetual (perp) markets to understand their trading options. This cookbook shows you how to use Mobula’s Pulse API to fetch all perp markets from supported exchanges like Gains Network and Lighter.
Supported Exchanges: Mobula currently indexes perp markets from:
  • Gains Network (gains-perp) - Trading on Arbitrum
  • Lighter (lighter-perp) - Trading on Lighter L2

Quick Start

Fetch Gains Network Perp Markets

curl -X GET "https://api.mobula.io/api/2/pulse?poolTypes=gains-perp" \
  -H "Authorization: YOUR_API_KEY"

Fetch Lighter Perp Markets

curl -X GET "https://api.mobula.io/api/2/pulse?poolTypes=lighter-perp" \
  -H "Authorization: YOUR_API_KEY"

Fetch All Perp Markets (Both Exchanges)

curl -X GET "https://api.mobula.io/api/2/pulse?poolTypes=gains-perp&poolTypes=lighter-perp" \
  -H "Authorization: YOUR_API_KEY"

Understanding Perp Market Pool Types

Pool TypeExchangeChainDescription
gains-perpGains NetworkArbitrum (evm:42161)Decentralized leveraged trading with synthetic assets
lighter-perpLighterLighter L2 (lighter:301, lighter:304)High-performance perpetual DEX with orderbook

Code Examples

JavaScript/TypeScript with Mobula SDK

import { MobulaClient } from '@mobula/sdk';

const client = new MobulaClient({
  apiKey: process.env.MOBULA_API_KEY
});

// Fetch Gains Network perp markets
async function getGainsPerpMarkets() {
  const response = await client.fetchPulse({
    poolTypes: ['gains-perp'],
    limit: 100
  });
  
  return response.data;
}

// Fetch Lighter perp markets
async function getLighterPerpMarkets() {
  const response = await client.fetchPulse({
    poolTypes: ['lighter-perp'],
    limit: 100
  });
  
  return response.data;
}

// Fetch all perp markets from both exchanges
async function getAllPerpMarkets() {
  const response = await client.fetchPulse({
    poolTypes: ['gains-perp', 'lighter-perp'],
    limit: 100
  });
  
  return response.data;
}

// Example usage
const markets = await getAllPerpMarkets();
console.log(`Found ${markets.length} perp markets`);
markets.forEach(market => {
  console.log(`${market.symbol}: ${market.name}`);
});

JavaScript with Fetch API

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.mobula.io/api/2';

// Fetch perp markets with specific pool types
async function fetchPerpMarkets(poolTypes) {
  const params = new URLSearchParams();
  poolTypes.forEach(type => params.append('poolTypes', type));
  params.append('limit', '100');

  const response = await fetch(`${BASE_URL}/pulse?${params}`, {
    headers: {
      'Authorization': API_KEY
    }
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Fetch Gains perp markets
const gainsMarkets = await fetchPerpMarkets(['gains-perp']);
console.log('Gains Network Perp Markets:', gainsMarkets);

// Fetch Lighter perp markets
const lighterMarkets = await fetchPerpMarkets(['lighter-perp']);
console.log('Lighter Perp Markets:', lighterMarkets);

// Fetch all perp markets
const allPerps = await fetchPerpMarkets(['gains-perp', 'lighter-perp']);
console.log('All Perp Markets:', allPerps);

Python

import requests

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.mobula.io/api/2'

def fetch_perp_markets(pool_types: list[str], limit: int = 100) -> dict:
    """Fetch perp markets from Mobula Pulse API."""
    params = {
        'poolTypes': pool_types,
        'limit': limit
    }
    
    response = requests.get(
        f'{BASE_URL}/pulse',
        params=params,
        headers={'Authorization': API_KEY}
    )
    response.raise_for_status()
    return response.json()

# Fetch Gains Network perp markets
gains_markets = fetch_perp_markets(['gains-perp'])
print(f"Gains Network markets: {len(gains_markets.get('data', []))}")

# Fetch Lighter perp markets
lighter_markets = fetch_perp_markets(['lighter-perp'])
print(f"Lighter markets: {len(lighter_markets.get('data', []))}")

# Fetch all perp markets
all_perps = fetch_perp_markets(['gains-perp', 'lighter-perp'])
print(f"Total perp markets: {len(all_perps.get('data', []))}")

# Display market details
for market in all_perps.get('data', []):
    print(f"- {market.get('symbol', 'N/A')}: {market.get('name', 'N/A')}")

Response Structure

The Pulse API returns perp market data in the following structure:
{
  "data": [
    {
      "address": "0x...",
      "chainId": "evm:42161",
      "symbol": "ETH-USD",
      "name": "Ethereum / USD",
      "poolType": "gains-perp",
      "exchange": "gains",
      "priceUSD": 3500.00,
      "volume24h": 1500000,
      "liquidity": 5000000,
      "trades24h": 1250
    }
  ]
}

Key Response Fields

FieldTypeDescription
addressstringMarket/pool contract address
chainIdstringBlockchain identifier (e.g., evm:42161, lighter:301)
symbolstringMarket trading pair symbol (e.g., ETH-USD, BTC-USD)
namestringFull market name
poolTypestringPool type (gains-perp or lighter-perp)
exchangestringExchange identifier (gains or lighter)
priceUSDnumberCurrent price in USD
volume24hnumber24-hour trading volume
liquiditynumberAvailable liquidity
trades24hnumberNumber of trades in last 24 hours

Filtering and Sorting

Filter by Chain

To get perp markets on a specific chain:
# Gains perps on Arbitrum only
curl -X GET "https://api.mobula.io/api/2/pulse?poolTypes=gains-perp&chainId=evm:42161" \
  -H "Authorization: YOUR_API_KEY"

Pagination

Use limit and offset parameters for paginated results:
# Get first 50 perp markets
curl -X GET "https://api.mobula.io/api/2/pulse?poolTypes=gains-perp&limit=50&offset=0" \
  -H "Authorization: YOUR_API_KEY"

# Get next 50 perp markets
curl -X GET "https://api.mobula.io/api/2/pulse?poolTypes=gains-perp&limit=50&offset=50" \
  -H "Authorization: YOUR_API_KEY"

Advanced: Using POST Method with Filters

For more complex queries, use the POST method with custom filters:
curl -X POST "https://api.mobula.io/api/2/pulse" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "poolTypes": ["gains-perp", "lighter-perp"],
    "limit": 100,
    "filters": {
      "volume_24h": { "gte": 100000 },
      "liquidity": { "gte": 50000 }
    },
    "sortBy": "volume_24h",
    "sortOrder": "desc"
  }'

TypeScript Example with Filters

import { MobulaClient } from '@mobula/sdk';

const client = new MobulaClient({
  apiKey: process.env.MOBULA_API_KEY
});

async function getHighVolumePerpMarkets() {
  const response = await client.fetchPulse({
    poolTypes: ['gains-perp', 'lighter-perp'],
    limit: 50,
    filters: {
      volume_24h: { gte: 100000 },
      liquidity: { gte: 50000 }
    },
    sortBy: 'volume_24h',
    sortOrder: 'desc'
  });

  console.log('High volume perp markets:');
  response.data.forEach(market => {
    console.log(`${market.symbol}: $${market.volume24h?.toLocaleString()} volume`);
  });

  return response.data;
}

Real-Time Perp Market Updates

For real-time updates on perp markets, use the Pulse V2 WebSocket stream:
import { MobulaClient } from '@mobula/sdk';

const client = new MobulaClient({
  apiKey: process.env.MOBULA_API_KEY
});

// Subscribe to perp markets updates
const subscriptionId = client.streams.subscribe(
  'pulse-v2',
  {
    poolTypes: ['gains-perp', 'lighter-perp'],
    compressed: false
  },
  (data) => {
    if (data.type === 'init') {
      console.log('Initial perp markets:', data.payload);
    }
    if (data.type === 'update-token') {
      console.log('Market update:', data.payload.token);
    }
  }
);

// Unsubscribe when done
// client.streams.unsubscribe('pulse-v2', subscriptionId);

Use Cases

1. Trading Bot Market Discovery

async function discoverTradableMarkets() {
  const markets = await getAllPerpMarkets();
  
  // Filter markets with sufficient liquidity for trading
  const tradableMarkets = markets.filter(m => 
    m.liquidity > 100000 && m.volume24h > 50000
  );
  
  return tradableMarkets.map(m => ({
    symbol: m.symbol,
    exchange: m.exchange,
    chainId: m.chainId,
    liquidity: m.liquidity
  }));
}

2. Market Analytics Dashboard

async function getMarketAnalytics() {
  const [gains, lighter] = await Promise.all([
    fetchPerpMarkets(['gains-perp']),
    fetchPerpMarkets(['lighter-perp'])
  ]);
  
  return {
    gains: {
      marketCount: gains.data.length,
      totalVolume: gains.data.reduce((sum, m) => sum + (m.volume24h || 0), 0),
      totalLiquidity: gains.data.reduce((sum, m) => sum + (m.liquidity || 0), 0)
    },
    lighter: {
      marketCount: lighter.data.length,
      totalVolume: lighter.data.reduce((sum, m) => sum + (m.volume24h || 0), 0),
      totalLiquidity: lighter.data.reduce((sum, m) => sum + (m.liquidity || 0), 0)
    }
  };
}

3. Building a Market Selector UI

import { useState, useEffect } from 'react';

function PerpMarketSelector({ onSelectMarket }) {
  const [markets, setMarkets] = useState([]);
  const [loading, setLoading] = useState(true);
  const [exchange, setExchange] = useState('all');

  useEffect(() => {
    async function loadMarkets() {
      setLoading(true);
      const poolTypes = exchange === 'all' 
        ? ['gains-perp', 'lighter-perp']
        : exchange === 'gains' 
          ? ['gains-perp'] 
          : ['lighter-perp'];
      
      const response = await fetchPerpMarkets(poolTypes);
      setMarkets(response.data);
      setLoading(false);
    }
    loadMarkets();
  }, [exchange]);

  if (loading) return <div>Loading markets...</div>;

  return (
    <div>
      <select value={exchange} onChange={(e) => setExchange(e.target.value)}>
        <option value="all">All Exchanges</option>
        <option value="gains">Gains Network</option>
        <option value="lighter">Lighter</option>
      </select>
      
      <ul>
        {markets.map((market) => (
          <li 
            key={`${market.chainId}-${market.address}`}
            onClick={() => onSelectMarket(market)}
          >
            {market.symbol} - {market.exchange}
          </li>
        ))}
      </ul>
    </div>
  );
}


Get Started

Create a free Mobula API key and start fetching perp markets today!

Need Help?