Skip to content

codifydoo/gamma-client

Repository files navigation

Gamma Client

A production-ready TypeScript client library for the Polymarket Gamma API (read-only market data).

npm version Build Status Coverage Status

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-client

Quick 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 return
  • params.offset? - Number of teams to skip
  • params.sport? - Filter by sport
  • params.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 return
  • params.offset? - Number of tags to skip
  • params.category? - Filter by category
  • params.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 ID
  • params.limit? - Number of relationships to return
  • params.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 slug
  • params.limit? - Number of relationships to return
  • params.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 ID
  • params.limit? - Number of related tags to return
  • params.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 slug
  • params.limit? - Number of related tags to return
  • params.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 return
  • params.offset? - Number of events to skip
  • params.active? - Filter by active status
  • params.category? - Filter by category
  • params.tags? - Filter by tags
  • params.startDate? - Filter by start date
  • params.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 return
  • params.offset? - Number of markets to skip
  • params.active? - Filter by active status
  • params.eventId? - Filter by event ID
  • params.category? - Filter by category
  • params.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 return
  • params.offset? - Number of series to skip
  • params.active? - Filter by active status
  • params.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 return
  • params.offset? - Number of comments to skip
  • params.marketId? - Filter by market ID
  • params.eventId? - Filter by event ID
  • params.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 address
  • params.limit? - Number of comments to return
  • params.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 return
  • params.offset? - Number of results to skip
  • params.types? - Filter by result types
  • params.category? - Filter by category
  • params.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 automatically

Caching

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 application

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

License

MIT License - see LICENSE file for details.

Support

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors