@codifydoo/gamma-client
v1.0.3
Published
TypeScript client library for Polymarket Gamma API (read-only market data)
Downloads
301
Maintainers
Readme
Gamma Client
A production-ready TypeScript client library for the Polymarket Gamma API (read-only market data).
Features
- 🚀 Full API Coverage - All 28+ endpoints across 8 domains
- 🔒 Type Safety - Strict TypeScript types with no
any - ✅ Runtime Validation - Zod schemas for request/response validation
- 🔄 Retry Logic - Exponential backoff with jitter for resilience
- ⚡ Rate Limiting - Token bucket implementation for polite API usage
- 💾 Caching - Optional in-memory TTL cache for performance
- 🔧 Normalization - Automatic parsing of JSON-encoded arrays
- 📖 Comprehensive Docs - JSDoc comments and runnable examples
Installation
npm install @codifydoo/gamma-clientQuick Start
import { GammaClient } from '@codifydoo/gamma-client';
const client = new GammaClient({
baseURL: 'https://gamma-api.polymarket.com',
timeoutMs: 10_000,
retries: 2,
rateLimit: { burst: 5, ratePerSec: 5 },
cache: { ttlMs: 5_000 },
userAgent: 'my-app/1.0.0',
});
// Health check
const health = await client.health.check();
console.log('API Status:', health.status);
// List active markets
const markets = await client.markets.list({
active: true,
limit: 10,
});
// Get market details with normalized data
const market = await client.markets.getBySlug('bitcoin-up-or-down-oct-2');
console.log('Outcomes:', market.outcomes); // ['Yes', 'No'] - automatically parsed
console.log('Prices:', market.outcomePrices); // [0.6, 0.4] - automatically parsed
// Search across markets, events, and profiles
const results = await client.search.query({
q: 'bitcoin',
types: ['market', 'event'],
limit: 20,
});Configuration
Client Options
interface GammaClientConfig {
baseURL?: string; // Default: 'https://gamma-api.polymarket.com'
timeoutMs?: number; // Default: 10_000
retries?: number; // Default: 2
rateLimit?: {
// Default: { burst: 5, ratePerSec: 5 }
burst: number;
ratePerSec: number;
};
cache?: {
// Default: { ttlMs: 5_000 }
ttlMs?: number; // Set to 0 to disable caching
};
userAgent?: string; // Default: 'gamma-client/1.0.0'
}Examples
Basic Usage
const client = new GammaClient();Custom Configuration
const client = new GammaClient({
baseURL: 'https://gamma-api.polymarket.com',
timeoutMs: 15_000,
retries: 3,
rateLimit: { burst: 10, ratePerSec: 8 },
cache: { ttlMs: 10_000 },
userAgent: 'my-trading-bot/1.0.0',
});No Caching
const client = new GammaClient({
cache: { ttlMs: 0 },
});API Reference
Health
client.health.check()
Check the health status of the Gamma API.
Returns: Promise<HealthCheckResponse>
const health = await client.health.check();
// { status: 'healthy', timestamp: '2024-01-01T00:00:00Z', ... }Sports
client.sports.listTeams(params?)
List all sports teams with optional filtering.
Parameters:
params.limit?- Number of teams to returnparams.offset?- Number of teams to skipparams.sport?- Filter by sportparams.league?- Filter by league
Returns: Promise<ListTeamsResponse>
const teams = await client.sports.listTeams({
sport: 'basketball',
limit: 10,
});client.sports.getMetadata()
Get sports metadata information.
Returns: Promise<SportsMetadataResponse>
const metadata = await client.sports.getMetadata();
// { sports: [{ id: '1', name: 'Basketball', leagues: [...] }] }Tags
client.tags.list(params?)
List all tags with optional filtering.
Parameters:
params.limit?- Number of tags to returnparams.offset?- Number of tags to skipparams.category?- Filter by categoryparams.search?- Search term
Returns: Promise<ListTagsResponse>
const tags = await client.tags.list({
category: 'politics',
limit: 20,
});client.tags.getById(id)
Get a tag by its ID.
Parameters:
id- Tag ID
Returns: Promise<Tag>
const tag = await client.tags.getById('123');client.tags.getBySlug(slug)
Get a tag by its slug.
Parameters:
slug- Tag slug
Returns: Promise<Tag>
const tag = await client.tags.getBySlug('us-elections');client.tags.getRelationshipsById(id, params?)
Get related tags relationships by tag ID.
Parameters:
id- Tag IDparams.limit?- Number of relationships to returnparams.offset?- Number of relationships to skip
Returns: Promise<TagRelationships>
const relationships = await client.tags.getRelationshipsById('123');client.tags.getRelationshipsBySlug(slug, params?)
Get related tags relationships by tag slug.
Parameters:
slug- Tag slugparams.limit?- Number of relationships to returnparams.offset?- Number of relationships to skip
Returns: Promise<TagRelationships>
const relationships = await client.tags.getRelationshipsBySlug('us-elections');client.tags.getRelatedToId(id, params?)
Get tags related to a tag ID.
Parameters:
id- Tag IDparams.limit?- Number of related tags to returnparams.offset?- Number of related tags to skip
Returns: Promise<Tag[]>
const relatedTags = await client.tags.getRelatedToId('123');client.tags.getRelatedToSlug(slug, params?)
Get tags related to a tag slug.
Parameters:
slug- Tag slugparams.limit?- Number of related tags to returnparams.offset?- Number of related tags to skip
Returns: Promise<Tag[]>
const relatedTags = await client.tags.getRelatedToSlug('us-elections');Events
client.events.list(params?)
List all events with optional filtering.
Parameters:
params.limit?- Number of events to returnparams.offset?- Number of events to skipparams.active?- Filter by active statusparams.category?- Filter by categoryparams.tags?- Filter by tagsparams.startDate?- Filter by start dateparams.endDate?- Filter by end date
Returns: Promise<ListEventsResponse>
const events = await client.events.list({
active: true,
category: 'politics',
limit: 50,
});client.events.getById(id)
Get an event by its ID.
Parameters:
id- Event ID
Returns: Promise<Event>
const event = await client.events.getById('123');client.events.getTags(eventId)
Get tags for an event.
Parameters:
eventId- Event ID
Returns: Promise<Tag[]>
const tags = await client.events.getTags('123');client.events.getBySlug(slug)
Get an event by its slug.
Parameters:
slug- Event slug
Returns: Promise<Event>
const event = await client.events.getBySlug('2024-presidential-election');Markets
client.markets.list(params?)
List all markets with optional filtering.
Parameters:
params.limit?- Number of markets to returnparams.offset?- Number of markets to skipparams.active?- Filter by active statusparams.eventId?- Filter by event IDparams.category?- Filter by categoryparams.tags?- Filter by tags
Returns: Promise<ListMarketsResponse>
const markets = await client.markets.list({
active: true,
limit: 100,
});client.markets.getById(id)
Get a market by its ID.
Parameters:
id- Market ID
Returns: Promise<Market>
const market = await client.markets.getById('123');client.markets.getTags(marketId)
Get tags for a market.
Parameters:
marketId- Market ID
Returns: Promise<Tag[]>
const tags = await client.markets.getTags('123');client.markets.getBySlug(slug)
Get a market by its slug.
Parameters:
slug- Market slug
Returns: Promise<Market>
const market = await client.markets.getBySlug('bitcoin-up-or-down-oct-2');Series
client.series.list(params?)
List all series with optional filtering.
Parameters:
params.limit?- Number of series to returnparams.offset?- Number of series to skipparams.active?- Filter by active statusparams.category?- Filter by category
Returns: Promise<ListSeriesResponse>
const series = await client.series.list({
active: true,
limit: 20,
});client.series.getById(id)
Get a series by its ID.
Parameters:
id- Series ID
Returns: Promise<Series>
const series = await client.series.getById('123');Comments
client.comments.list(params?)
List all comments with optional filtering.
Parameters:
params.limit?- Number of comments to returnparams.offset?- Number of comments to skipparams.marketId?- Filter by market IDparams.eventId?- Filter by event IDparams.parentId?- Filter by parent comment ID
Returns: Promise<ListCommentsResponse>
const comments = await client.comments.list({
marketId: '123',
limit: 50,
});client.comments.getById(id)
Get a comment by its ID.
Parameters:
id- Comment ID
Returns: Promise<Comment>
const comment = await client.comments.getById('123');client.comments.getByUserAddress(address, params?)
Get comments by user address.
Parameters:
address- User addressparams.limit?- Number of comments to returnparams.offset?- Number of comments to skip
Returns: Promise<ListCommentsResponse>
const comments = await client.comments.getByUserAddress('0x123...', {
limit: 20,
});Search
client.search.query(params)
Search markets, events, and profiles.
Parameters:
params.q- Search query (required)params.limit?- Number of results to returnparams.offset?- Number of results to skipparams.types?- Filter by result typesparams.category?- Filter by categoryparams.tags?- Filter by tags
Returns: Promise<SearchResponse>
const results = await client.search.query({
q: 'bitcoin',
types: ['market', 'event'],
limit: 20,
});Data Normalization
The Gamma API returns some fields as JSON-encoded strings. The client automatically normalizes these fields:
Market Data
const market = await client.markets.getById('123');
// These fields are automatically parsed from JSON strings:
console.log(market.outcomes); // ['Yes', 'No'] instead of '["Yes", "No"]'
console.log(market.outcomePrices); // [0.6, 0.4] instead of '[0.6, 0.4]'
console.log(market.clobTokenIds); // ['token1', 'token2'] instead of '["token1", "token2"]'Manual Normalization
You can also use the normalization utilities directly:
import { parseJsonArray, toNumber, toNumberArray, toStringArray } from '@codifydoo/gamma-client';
const jsonString = '["a", "b", "c"]';
const parsed = parseJsonArray(jsonString); // ['a', 'b', 'c']
const numberString = '123.45';
const number = toNumber(numberString); // 123.45
const numberArrayString = '[1, 2, 3]';
const numbers = toNumberArray(numberArrayString); // [1, 2, 3]Pagination
The client supports both offset-based and cursor-based pagination:
Offset Pagination
// Get first page
const page1 = await client.markets.list({ limit: 10, offset: 0 });
// Get second page
const page2 = await client.markets.list({ limit: 10, offset: 10 });
// Check if there are more results
if (page1.hasMore) {
console.log('More results available');
}Cursor Pagination
// Get first page
const page1 = await client.events.list({ limit: 10 });
// Get next page using cursor
if (page1.nextCursor) {
const page2 = await client.events.list({
limit: 10,
cursor: page1.nextCursor,
});
}Error Handling
The client provides comprehensive error handling:
import { GammaClientError } from '@codifydoo/gamma-client';
try {
const market = await client.markets.getById('invalid-id');
} catch (error) {
if (error instanceof GammaClientError) {
console.error('API Error:', error.message);
console.error('Status Code:', error.statusCode);
console.error('Endpoint:', error.endpoint);
} else {
console.error('Unexpected error:', error);
}
}Common Error Scenarios
Network Errors
try {
const result = await client.markets.list();
} catch (error) {
// Network errors are automatically retried with exponential backoff
console.error('Request failed after retries:', error.message);
}Validation Errors
try {
const result = await client.markets.list({ limit: -1 }); // Invalid limit
} catch (error) {
// Zod validation error
console.error('Validation error:', error.message);
}Rate Limiting
// The client automatically handles rate limiting
// Requests are queued and executed at the configured rate
const promises = Array(100)
.fill(null)
.map(() => client.markets.list());
await Promise.all(promises); // Will be rate-limited automaticallyCaching
The client includes an optional in-memory cache:
const client = new GammaClient({
cache: { ttlMs: 10_000 }, // Cache for 10 seconds
});
// First call - hits API
const market1 = await client.markets.getById('123');
// Second call within 10 seconds - hits cache
const market2 = await client.markets.getById('123');
// Clear cache
client.clearCache();
// Get cache statistics
const stats = client.getCacheStats();
console.log('Cache size:', stats?.size);Rate Limiting
The client implements a token bucket rate limiter:
const client = new GammaClient({
rateLimit: {
burst: 10, // Allow up to 10 requests immediately
ratePerSec: 5, // Then limit to 5 requests per second
},
});
// These requests will be rate-limited automatically
const promises = Array(20)
.fill(null)
.map(() => client.markets.list());
await Promise.all(promises);Best Practices
1. Error Handling
Always wrap API calls in try-catch blocks:
try {
const result = await client.markets.list();
// Process result
} catch (error) {
// Handle error appropriately
console.error('Failed to fetch markets:', error.message);
}2. Pagination
Use pagination to avoid loading too much data at once:
async function getAllMarkets() {
const allMarkets = [];
let offset = 0;
const limit = 100;
while (true) {
const response = await client.markets.list({ limit, offset });
allMarkets.push(...response.data);
if (!response.hasMore) break;
offset += limit;
}
return allMarkets;
}3. Caching
Enable caching for frequently accessed data:
const client = new GammaClient({
cache: { ttlMs: 30_000 }, // Cache for 30 seconds
});4. Rate Limiting
Configure appropriate rate limits for your use case:
const client = new GammaClient({
rateLimit: {
burst: 5, // Conservative burst
ratePerSec: 2, // Conservative rate
},
});5. Type Safety
Use TypeScript strict mode and leverage the provided types:
import { Market, ListMarketsRequest } from '@codifydoo/gamma-client';
async function processMarkets(params: ListMarketsRequest): Promise<Market[]> {
const response = await client.markets.list(params);
return response.data;
}Troubleshooting
Common Issues
1. Network Timeouts
const client = new GammaClient({
timeoutMs: 30_000, // Increase timeout for slow connections
});2. Rate Limiting
const client = new GammaClient({
rateLimit: {
burst: 1, // Reduce burst
ratePerSec: 1, // Reduce rate
},
});3. Memory Usage
const client = new GammaClient({
cache: { ttlMs: 0 }, // Disable caching to reduce memory usage
});4. Validation Errors
Check the error message for specific validation issues:
try {
await client.markets.list({ limit: -1 });
} catch (error) {
console.error('Validation error:', error.message);
// Look for specific field validation errors
}Debug Mode
Enable debug logging to see request details:
// The client logs requests at debug level
// Enable debug logging in your applicationContributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details.
