Skip to main content
Glama

CoinGecko MCP - Cryptocurrency Price & Market Data

Official
client.ts32.7 kB
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import type { RequestInit, RequestInfo, BodyInit } from './internal/builtin-types'; import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestInit } from './internal/types'; import { uuid4 } from './internal/utils/uuid'; import { validatePositiveInteger, isAbsoluteURL, safeJSON } from './internal/utils/values'; import { sleep } from './internal/utils/sleep'; export type { Logger, LogLevel } from './internal/utils/log'; import { castToError, isAbortError } from './internal/errors'; import type { APIResponseProps } from './internal/parse'; import { getPlatformHeaders } from './internal/detect-platform'; import * as Shims from './internal/shims'; import * as Opts from './internal/request-options'; import { VERSION } from './version'; import * as Errors from './core/error'; import * as Uploads from './core/uploads'; import * as API from './resources/index'; import { APIPromise } from './core/api-promise'; import { AssetPlatformGetParams, AssetPlatformGetResponse, AssetPlatforms, } from './resources/asset-platforms'; import { Entities, EntityGetListParams, EntityGetListResponse } from './resources/entities'; import { ExchangeRateGetResponse, ExchangeRates } from './resources/exchange-rates'; import { Key, KeyGetResponse } from './resources/key'; import { Ping, PingGetResponse } from './resources/ping'; import { PublicTreasury, PublicTreasuryGetCoinIDParams, PublicTreasuryGetCoinIDResponse, PublicTreasuryGetEntityIDResponse, } from './resources/public-treasury'; import { TokenListGetAllJsonResponse, TokenLists } from './resources/token-lists'; import { CoinGetIDParams, CoinGetIDResponse, Coins } from './resources/coins/coins'; import { DerivativeGetResponse, Derivatives } from './resources/derivatives/derivatives'; import { ExchangeGetIDParams, ExchangeGetIDResponse, ExchangeGetListParams, ExchangeGetListResponse, ExchangeGetParams, ExchangeGetResponse, Exchanges, } from './resources/exchanges/exchanges'; import { Global, GlobalGetResponse } from './resources/global/global'; import { NFTGetIDResponse, NFTGetListParams, NFTGetListResponse, NFTGetMarketsParams, NFTGetMarketsResponse, NFTs, } from './resources/nfts/nfts'; import { Onchain } from './resources/onchain/onchain'; import { Search, SearchGetParams, SearchGetResponse } from './resources/search/search'; import { Simple } from './resources/simple/simple'; import { type Fetch } from './internal/builtin-types'; import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; import { FinalRequestOptions, RequestOptions } from './internal/request-options'; import { readEnv } from './internal/utils/env'; import { type LogLevel, type Logger, formatRequestDetails, loggerFor, parseLogLevel, } from './internal/utils/log'; import { isEmptyObj } from './internal/utils/values'; const environments = { pro: 'https://pro-api.coingecko.com/api/v3', demo: 'https://api.coingecko.com/api/v3', }; type Environment = keyof typeof environments; export interface ClientOptions { /** * CoinGecko Pro API Key */ proAPIKey?: string | null | undefined; /** * CoinGecko Demo API Key */ demoAPIKey?: string | null | undefined; /** * Specifies the environment to use for the API. * * Each environment maps to a different base URL: * - `pro` corresponds to `https://pro-api.coingecko.com/api/v3` * - `demo` corresponds to `https://api.coingecko.com/api/v3` */ environment?: Environment | undefined; /** * Override the default base URL for the API, e.g., "https://api.example.com/v2/" * * Defaults to process.env['COINGECKO_BASE_URL']. */ baseURL?: string | null | undefined; /** * The maximum amount of time (in milliseconds) that the client should wait for a response * from the server before timing out a single request. * * Note that request timeouts are retried by default, so in a worst-case scenario you may wait * much longer than this timeout before the promise succeeds or fails. * * @unit milliseconds */ timeout?: number | undefined; /** * Additional `RequestInit` options to be passed to `fetch` calls. * Properties will be overridden by per-request `fetchOptions`. */ fetchOptions?: MergedRequestInit | undefined; /** * Specify a custom `fetch` function implementation. * * If not provided, we expect that `fetch` is defined globally. */ fetch?: Fetch | undefined; /** * The maximum number of times that the client will retry a request in case of a * temporary failure, like a network error or a 5XX error from the server. * * @default 2 */ maxRetries?: number | undefined; /** * Default headers to include with every request to the API. * * These can be removed in individual requests by explicitly setting the * header to `null` in request options. */ defaultHeaders?: HeadersLike | undefined; /** * Default query parameters to include with every request to the API. * * These can be removed in individual requests by explicitly setting the * param to `undefined` in request options. */ defaultQuery?: Record<string, string | undefined> | undefined; /** * Set the log level. * * Defaults to process.env['COINGECKO_LOG'] or 'warn' if it isn't set. */ logLevel?: LogLevel | undefined; /** * Set the logger. * * Defaults to globalThis.console. */ logger?: Logger | undefined; } /** * API Client for interfacing with the Coingecko API. */ export class Coingecko { proAPIKey: string | null; demoAPIKey: string | null; baseURL: string; maxRetries: number; timeout: number; logger: Logger | undefined; logLevel: LogLevel | undefined; fetchOptions: MergedRequestInit | undefined; private fetch: Fetch; #encoder: Opts.RequestEncoder; protected idempotencyHeader?: string; private _options: ClientOptions; /** * API Client for interfacing with the Coingecko API. * * @param {string | null | undefined} [opts.proAPIKey=process.env['COINGECKO_PRO_API_KEY'] ?? null] * @param {string | null | undefined} [opts.demoAPIKey=process.env['COINGECKO_DEMO_API_KEY'] ?? null] * @param {Environment} [opts.environment=pro] - Specifies the environment URL to use for the API. * @param {string} [opts.baseURL=process.env['COINGECKO_BASE_URL'] ?? https://pro-api.coingecko.com/api/v3] - Override the default base URL for the API. * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls. * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API. * @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API. */ constructor({ baseURL = readEnv('COINGECKO_BASE_URL'), proAPIKey = readEnv('COINGECKO_PRO_API_KEY') ?? null, demoAPIKey = readEnv('COINGECKO_DEMO_API_KEY') ?? null, ...opts }: ClientOptions = {}) { const options: ClientOptions = { proAPIKey, demoAPIKey, ...opts, baseURL, environment: opts.environment ?? 'pro', }; if (baseURL && opts.environment) { throw new Errors.CoingeckoError( 'Ambiguous URL; The `baseURL` option (or COINGECKO_BASE_URL env var) and the `environment` option are given. If you want to use the environment you must pass baseURL: null', ); } this.baseURL = options.baseURL || environments[options.environment || 'pro']; this.timeout = options.timeout ?? Coingecko.DEFAULT_TIMEOUT /* 1 minute */; this.logger = options.logger ?? console; const defaultLogLevel = 'warn'; // Set default logLevel early so that we can log a warning in parseLogLevel. this.logLevel = defaultLogLevel; this.logLevel = parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? parseLogLevel(readEnv('COINGECKO_LOG'), "process.env['COINGECKO_LOG']", this) ?? defaultLogLevel; this.fetchOptions = options.fetchOptions; this.maxRetries = options.maxRetries ?? 2; this.fetch = options.fetch ?? Shims.getDefaultFetch(); this.#encoder = Opts.FallbackEncoder; this._options = options; this.proAPIKey = proAPIKey; this.demoAPIKey = demoAPIKey; } /** * Create a new client instance re-using the same options given to the current client with optional overriding. */ withOptions(options: Partial<ClientOptions>): this { const client = new (this.constructor as any as new (props: ClientOptions) => typeof this)({ ...this._options, environment: options.environment ? options.environment : undefined, baseURL: options.environment ? undefined : this.baseURL, maxRetries: this.maxRetries, timeout: this.timeout, logger: this.logger, logLevel: this.logLevel, fetch: this.fetch, fetchOptions: this.fetchOptions, proAPIKey: this.proAPIKey, demoAPIKey: this.demoAPIKey, ...options, }); return client; } /** * Check whether the base URL is set to its default. */ #baseURLOverridden(): boolean { return this.baseURL !== environments[this._options.environment || 'pro']; } protected defaultQuery(): Record<string, string | undefined> | undefined { return this._options.defaultQuery; } protected validateHeaders({ values, nulls }: NullableHeaders) { if (this.proAPIKey && values.get('x-cg-pro-api-key')) { return; } if (nulls.has('x-cg-pro-api-key')) { return; } if (this.demoAPIKey && values.get('x-cg-demo-api-key')) { return; } if (nulls.has('x-cg-demo-api-key')) { return; } throw new Error( 'Could not resolve authentication method. Expected either proAPIKey or demoAPIKey to be set. Or for one of the "x-cg-pro-api-key" or "x-cg-demo-api-key" headers to be explicitly omitted', ); } protected async authHeaders(opts: FinalRequestOptions): Promise<NullableHeaders | undefined> { return buildHeaders([await this.proKeyAuth(opts), await this.demoKeyAuth(opts)]); } protected async proKeyAuth(opts: FinalRequestOptions): Promise<NullableHeaders | undefined> { if (this.proAPIKey == null) { return undefined; } return buildHeaders([{ 'x-cg-pro-api-key': this.proAPIKey }]); } protected async demoKeyAuth(opts: FinalRequestOptions): Promise<NullableHeaders | undefined> { if (this.demoAPIKey == null) { return undefined; } return buildHeaders([{ 'x-cg-demo-api-key': this.demoAPIKey }]); } /** * Basic re-implementation of `qs.stringify` for primitive types. */ protected stringifyQuery(query: Record<string, unknown>): string { return Object.entries(query) .filter(([_, value]) => typeof value !== 'undefined') .map(([key, value]) => { if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; } if (value === null) { return `${encodeURIComponent(key)}=`; } throw new Errors.CoingeckoError( `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`, ); }) .join('&'); } private getUserAgent(): string { return `${this.constructor.name}/JS ${VERSION}`; } protected defaultIdempotencyKey(): string { return `stainless-node-retry-${uuid4()}`; } protected makeStatusError( status: number, error: Object, message: string | undefined, headers: Headers, ): Errors.APIError { return Errors.APIError.generate(status, error, message, headers); } buildURL( path: string, query: Record<string, unknown> | null | undefined, defaultBaseURL?: string | undefined, ): string { const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL; const url = isAbsoluteURL(path) ? new URL(path) : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); const defaultQuery = this.defaultQuery(); if (!isEmptyObj(defaultQuery)) { query = { ...defaultQuery, ...query }; } if (typeof query === 'object' && query && !Array.isArray(query)) { url.search = this.stringifyQuery(query as Record<string, unknown>); } return url.toString(); } /** * Used as a callback for mutating the given `FinalRequestOptions` object. */ protected async prepareOptions(options: FinalRequestOptions): Promise<void> {} /** * Used as a callback for mutating the given `RequestInit` object. * * This is useful for cases where you want to add certain headers based off of * the request properties, e.g. `method` or `url`. */ protected async prepareRequest( request: RequestInit, { url, options }: { url: string; options: FinalRequestOptions }, ): Promise<void> {} get<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { return this.methodRequest('get', path, opts); } post<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { return this.methodRequest('post', path, opts); } patch<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { return this.methodRequest('patch', path, opts); } put<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { return this.methodRequest('put', path, opts); } delete<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { return this.methodRequest('delete', path, opts); } private methodRequest<Rsp>( method: HTTPMethod, path: string, opts?: PromiseOrValue<RequestOptions>, ): APIPromise<Rsp> { return this.request( Promise.resolve(opts).then((opts) => { return { method, path, ...opts }; }), ); } request<Rsp>( options: PromiseOrValue<FinalRequestOptions>, remainingRetries: number | null = null, ): APIPromise<Rsp> { return new APIPromise(this, this.makeRequest(options, remainingRetries, undefined)); } private async makeRequest( optionsInput: PromiseOrValue<FinalRequestOptions>, retriesRemaining: number | null, retryOfRequestLogID: string | undefined, ): Promise<APIResponseProps> { const options = await optionsInput; const maxRetries = options.maxRetries ?? this.maxRetries; if (retriesRemaining == null) { retriesRemaining = maxRetries; } await this.prepareOptions(options); const { req, url, timeout } = await this.buildRequest(options, { retryCount: maxRetries - retriesRemaining, }); await this.prepareRequest(req, { url, options }); /** Not an API request ID, just for correlating local log entries. */ const requestLogID = 'log_' + ((Math.random() * (1 << 24)) | 0).toString(16).padStart(6, '0'); const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`; const startTime = Date.now(); loggerFor(this).debug( `[${requestLogID}] sending request`, formatRequestDetails({ retryOfRequestLogID, method: options.method, url, options, headers: req.headers, }), ); if (options.signal?.aborted) { throw new Errors.APIUserAbortError(); } const controller = new AbortController(); const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); const headersTime = Date.now(); if (response instanceof globalThis.Error) { const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; if (options.signal?.aborted) { throw new Errors.APIUserAbortError(); } // detect native connection timeout errors // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)" // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)" // others do not provide enough information to distinguish timeouts from other connection errors const isTimeout = isAbortError(response) || /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')); if (retriesRemaining) { loggerFor(this).info( `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`, ); loggerFor(this).debug( `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url, durationMs: headersTime - startTime, message: response.message, }), ); return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID); } loggerFor(this).info( `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`, ); loggerFor(this).debug( `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, formatRequestDetails({ retryOfRequestLogID, url, durationMs: headersTime - startTime, message: response.message, }), ); if (isTimeout) { throw new Errors.APIConnectionTimeoutError(); } throw new Errors.APIConnectionError({ cause: response }); } const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${ response.ok ? 'succeeded' : 'failed' } with status ${response.status} in ${headersTime - startTime}ms`; if (!response.ok) { const shouldRetry = await this.shouldRetry(response); if (retriesRemaining && shouldRetry) { const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; // We don't need the body of this response. await Shims.CancelReadableStream(response.body); loggerFor(this).info(`${responseInfo} - ${retryMessage}`); loggerFor(this).debug( `[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, durationMs: headersTime - startTime, }), ); return this.retryRequest( options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers, ); } const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`; loggerFor(this).info(`${responseInfo} - ${retryMessage}`); const errText = await response.text().catch((err: any) => castToError(err).message); const errJSON = safeJSON(errText); const errMessage = errJSON ? undefined : errText; loggerFor(this).debug( `[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, message: errMessage, durationMs: Date.now() - startTime, }), ); const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers); throw err; } loggerFor(this).info(responseInfo); loggerFor(this).debug( `[${requestLogID}] response start`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, durationMs: headersTime - startTime, }), ); return { response, options, controller, requestLogID, retryOfRequestLogID, startTime }; } async fetchWithTimeout( url: RequestInfo, init: RequestInit | undefined, ms: number, controller: AbortController, ): Promise<Response> { const { signal, method, ...options } = init || {}; if (signal) signal.addEventListener('abort', () => controller.abort()); const timeout = setTimeout(() => controller.abort(), ms); const isReadableBody = ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body); const fetchOptions: RequestInit = { signal: controller.signal as any, ...(isReadableBody ? { duplex: 'half' } : {}), method: 'GET', ...options, }; if (method) { // Custom methods like 'patch' need to be uppercased // See https://github.com/nodejs/undici/issues/2294 fetchOptions.method = method.toUpperCase(); } try { // use undefined this binding; fetch errors if bound to something else in browser/cloudflare return await this.fetch.call(undefined, url, fetchOptions); } finally { clearTimeout(timeout); } } private async shouldRetry(response: Response): Promise<boolean> { // Note this is not a standard header. const shouldRetryHeader = response.headers.get('x-should-retry'); // If the server explicitly says whether or not to retry, obey. if (shouldRetryHeader === 'true') return true; if (shouldRetryHeader === 'false') return false; // Retry on request timeouts. if (response.status === 408) return true; // Retry on lock timeouts. if (response.status === 409) return true; // Retry on rate limits. if (response.status === 429) return true; // Retry internal errors. if (response.status >= 500) return true; return false; } private async retryRequest( options: FinalRequestOptions, retriesRemaining: number, requestLogID: string, responseHeaders?: Headers | undefined, ): Promise<APIResponseProps> { let timeoutMillis: number | undefined; // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it. const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms'); if (retryAfterMillisHeader) { const timeoutMs = parseFloat(retryAfterMillisHeader); if (!Number.isNaN(timeoutMs)) { timeoutMillis = timeoutMs; } } // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After const retryAfterHeader = responseHeaders?.get('retry-after'); if (retryAfterHeader && !timeoutMillis) { const timeoutSeconds = parseFloat(retryAfterHeader); if (!Number.isNaN(timeoutSeconds)) { timeoutMillis = timeoutSeconds * 1000; } else { timeoutMillis = Date.parse(retryAfterHeader) - Date.now(); } } // If the API asks us to wait a certain amount of time (and it's a reasonable amount), // just do what it says, but otherwise calculate a default if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) { const maxRetries = options.maxRetries ?? this.maxRetries; timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries); } await sleep(timeoutMillis); return this.makeRequest(options, retriesRemaining - 1, requestLogID); } private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number { const initialRetryDelay = 0.5; const maxRetryDelay = 8.0; const numRetries = maxRetries - retriesRemaining; // Apply exponential backoff, but not more than the max. const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay); // Apply some jitter, take up to at most 25 percent of the retry time. const jitter = 1 - Math.random() * 0.25; return sleepSeconds * jitter * 1000; } async buildRequest( inputOptions: FinalRequestOptions, { retryCount = 0 }: { retryCount?: number } = {}, ): Promise<{ req: FinalizedRequestInit; url: string; timeout: number }> { const options = { ...inputOptions }; const { method, path, query, defaultBaseURL } = options; const url = this.buildURL(path!, query as Record<string, unknown>, defaultBaseURL); if ('timeout' in options) validatePositiveInteger('timeout', options.timeout); options.timeout = options.timeout ?? this.timeout; const { bodyHeaders, body } = this.buildBody({ options }); const reqHeaders = await this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount }); const req: FinalizedRequestInit = { method, headers: reqHeaders, ...(options.signal && { signal: options.signal }), ...((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream && { duplex: 'half' }), ...(body && { body }), ...((this.fetchOptions as any) ?? {}), ...((options.fetchOptions as any) ?? {}), }; return { req, url, timeout: options.timeout }; } private async buildHeaders({ options, method, bodyHeaders, retryCount, }: { options: FinalRequestOptions; method: HTTPMethod; bodyHeaders: HeadersLike; retryCount: number; }): Promise<Headers> { let idempotencyHeaders: HeadersLike = {}; if (this.idempotencyHeader && method !== 'get') { if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey; } const headers = buildHeaders([ idempotencyHeaders, { Accept: 'application/json', 'User-Agent': this.getUserAgent(), 'X-Stainless-Retry-Count': String(retryCount), ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), ...getPlatformHeaders(), }, await this.authHeaders(options), this._options.defaultHeaders, bodyHeaders, options.headers, ]); this.validateHeaders(headers); return headers.values; } private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): { bodyHeaders: HeadersLike; body: BodyInit | undefined; } { if (!body) { return { bodyHeaders: undefined, body: undefined }; } const headers = buildHeaders([rawHeaders]); if ( // Pass raw type verbatim ArrayBuffer.isView(body) || body instanceof ArrayBuffer || body instanceof DataView || (typeof body === 'string' && // Preserve legacy string encoding behavior for now headers.values.has('content-type')) || // `Blob` is superset of `File` ((globalThis as any).Blob && body instanceof (globalThis as any).Blob) || // `FormData` -> `multipart/form-data` body instanceof FormData || // `URLSearchParams` -> `application/x-www-form-urlencoded` body instanceof URLSearchParams || // Send chunked stream (each chunk has own `length`) ((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream) ) { return { bodyHeaders: undefined, body: body as BodyInit }; } else if ( typeof body === 'object' && (Symbol.asyncIterator in body || (Symbol.iterator in body && 'next' in body && typeof body.next === 'function')) ) { return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable<Uint8Array>) }; } else { return this.#encoder({ body, headers }); } } static Coingecko = this; static DEFAULT_TIMEOUT = 60000; // 1 minute static CoingeckoError = Errors.CoingeckoError; static APIError = Errors.APIError; static APIConnectionError = Errors.APIConnectionError; static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError; static APIUserAbortError = Errors.APIUserAbortError; static NotFoundError = Errors.NotFoundError; static ConflictError = Errors.ConflictError; static RateLimitError = Errors.RateLimitError; static BadRequestError = Errors.BadRequestError; static AuthenticationError = Errors.AuthenticationError; static InternalServerError = Errors.InternalServerError; static PermissionDeniedError = Errors.PermissionDeniedError; static UnprocessableEntityError = Errors.UnprocessableEntityError; static toFile = Uploads.toFile; assetPlatforms: API.AssetPlatforms = new API.AssetPlatforms(this); coins: API.Coins = new API.Coins(this); derivatives: API.Derivatives = new API.Derivatives(this); entities: API.Entities = new API.Entities(this); exchangeRates: API.ExchangeRates = new API.ExchangeRates(this); exchanges: API.Exchanges = new API.Exchanges(this); global: API.Global = new API.Global(this); key: API.Key = new API.Key(this); nfts: API.NFTs = new API.NFTs(this); onchain: API.Onchain = new API.Onchain(this); ping: API.Ping = new API.Ping(this); publicTreasury: API.PublicTreasury = new API.PublicTreasury(this); search: API.Search = new API.Search(this); simple: API.Simple = new API.Simple(this); tokenLists: API.TokenLists = new API.TokenLists(this); } Coingecko.AssetPlatforms = AssetPlatforms; Coingecko.Coins = Coins; Coingecko.Derivatives = Derivatives; Coingecko.Entities = Entities; Coingecko.ExchangeRates = ExchangeRates; Coingecko.Exchanges = Exchanges; Coingecko.Global = Global; Coingecko.Key = Key; Coingecko.NFTs = NFTs; Coingecko.Onchain = Onchain; Coingecko.Ping = Ping; Coingecko.PublicTreasury = PublicTreasury; Coingecko.Search = Search; Coingecko.Simple = Simple; Coingecko.TokenLists = TokenLists; export declare namespace Coingecko { export type RequestOptions = Opts.RequestOptions; export { AssetPlatforms as AssetPlatforms, type AssetPlatformGetResponse as AssetPlatformGetResponse, type AssetPlatformGetParams as AssetPlatformGetParams, }; export { Coins as Coins, type CoinGetIDResponse as CoinGetIDResponse, type CoinGetIDParams as CoinGetIDParams, }; export { Derivatives as Derivatives, type DerivativeGetResponse as DerivativeGetResponse }; export { Entities as Entities, type EntityGetListResponse as EntityGetListResponse, type EntityGetListParams as EntityGetListParams, }; export { ExchangeRates as ExchangeRates, type ExchangeRateGetResponse as ExchangeRateGetResponse }; export { Exchanges as Exchanges, type ExchangeGetResponse as ExchangeGetResponse, type ExchangeGetIDResponse as ExchangeGetIDResponse, type ExchangeGetListResponse as ExchangeGetListResponse, type ExchangeGetParams as ExchangeGetParams, type ExchangeGetIDParams as ExchangeGetIDParams, type ExchangeGetListParams as ExchangeGetListParams, }; export { Global as Global, type GlobalGetResponse as GlobalGetResponse }; export { Key as Key, type KeyGetResponse as KeyGetResponse }; export { NFTs as NFTs, type NFTGetIDResponse as NFTGetIDResponse, type NFTGetListResponse as NFTGetListResponse, type NFTGetMarketsResponse as NFTGetMarketsResponse, type NFTGetListParams as NFTGetListParams, type NFTGetMarketsParams as NFTGetMarketsParams, }; export { Onchain as Onchain }; export { Ping as Ping, type PingGetResponse as PingGetResponse }; export { PublicTreasury as PublicTreasury, type PublicTreasuryGetCoinIDResponse as PublicTreasuryGetCoinIDResponse, type PublicTreasuryGetEntityIDResponse as PublicTreasuryGetEntityIDResponse, type PublicTreasuryGetCoinIDParams as PublicTreasuryGetCoinIDParams, }; export { Search as Search, type SearchGetResponse as SearchGetResponse, type SearchGetParams as SearchGetParams, }; export { Simple as Simple }; export { TokenLists as TokenLists, type TokenListGetAllJsonResponse as TokenListGetAllJsonResponse }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/coingecko/coingecko-typescript'

If you have feedback or need assistance with the MCP directory API, please join our Discord server