Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ PROVIDER_KEY_OPENWEATHER=CHANGE_ME
PROVIDER_KEY_COINGECKO=CHANGE_ME
PROVIDER_KEY_POLYMARKET=CHANGE_ME
PROVIDER_KEY_AVIASALES=CHANGE_ME
PROVIDER_KEY_XQUIK=CHANGE_ME
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# APIbase.pro — The API Hub for AI Agents

> One MCP endpoint. 618 tools. 191 providers. Pay per call with x402 (USDC on Base) or MPP (USDC on Tempo).
> One MCP endpoint. 622 tools. 192 providers. Pay per call with x402 (USDC on Base) or MPP (USDC on Tempo).

**[Live Platform](https://apibase.pro)** | **[Tool Catalog](https://apibase.pro/api/v1/tools)** | **[MCP Endpoint](https://apibase.pro/mcp)** | **[Frameworks](https://apibase.pro/frameworks)** | **[Dashboard](https://apibase.pro/dashboard)**

Expand All @@ -27,7 +27,7 @@ https://github.com/user-attachments/assets/9e598d61-b2d0-486c-bd34-f0cb0354d09c

## What is APIbase?

Production MCP server that gives AI agents access to 618 real-world API tools through a single endpoint. Agents connect once to `https://apibase.pro/mcp` and can search flights, get stock quotes, check weather and tides, query US Census and CDC health data, search ML models on HuggingFace, look up World Bank indicators, track streamflow from USGS stations, search 7M+ CS papers on DBLP, generate images, send emails, decode VINs, look up chemical compounds, scan npm/PyPI vulnerabilities, search NIST NVD CVE records, find EV chargers, estimate solar PV output, search art at the Met Museum, look up Dota 2 match stats, get decoded aviation METAR/TAF, look up parsed NOTAMs and PIREPs, batch multiple calls, track usage analytics — and 300+ more tools across 30+ categories.
Production MCP server that gives AI agents access to 622 real-world API tools through a single endpoint. Agents connect once to `https://apibase.pro/mcp` and can search flights, get stock quotes, check weather and tides, query US Census and CDC health data, search ML models on HuggingFace, look up World Bank indicators, track streamflow from USGS stations, search 7M+ CS papers on DBLP, generate images, send emails, decode VINs, look up chemical compounds, scan npm/PyPI vulnerabilities, search NIST NVD CVE records, find EV chargers, estimate solar PV output, search art at the Met Museum, look up Dota 2 match stats, get decoded aviation METAR/TAF, look up parsed NOTAMs and PIREPs, search X/Twitter posts and profiles, batch multiple calls, track usage analytics — and 300+ more tools across 30+ categories.

**Built for AI agents, not humans.** Auto-registration, zero setup, pay-per-call via x402 USDC micropayments on Base or MPP (Machine Payments Protocol) on Tempo.

Expand Down Expand Up @@ -91,13 +91,13 @@ curl -X POST https://apibase.pro/api/v1/tools/finnhub.quote/call \

---

## Tool Categories (618 tools, 191 providers)
## Tool Categories (622 tools, 192 providers)

| Category | Tools | Providers | Examples |
|----------|-------|-----------|----------|
| **Web Search** | 11 | Serper, Tavily, Exa, Spider.cloud | Google search, AI search, semantic search, web scraping |
| **News & Events** | 10 | NewsData, GDELT, Mastodon, Currents API | Global news (65 langs), crypto news, trending |
| **Social** | 7 | Bluesky, TwitterAPI.io | Search posts, profiles, feeds (AT Protocol, X/Twitter) |
| **Social** | 11 | Bluesky, TwitterAPI.io, Xquik | Search posts, profiles, feeds, followers, trends (AT Protocol, X/Twitter) |
| **Travel & Flights** | 20 | Amadeus, Sabre, Aviasales, IRCTC Indian Railways | Flight search, pricing, status, airports, Indian train schedules/live status |
| **Finance & Stocks** | 17 | Finnhub, CoinGecko, ECB, FRED, World Bank | Stock quotes, OHLCV, FX rates, economic data, global indicators |
| **Banking Data** | 7 | FDIC BankFind, IBANAPI, Razorpay IFSC | US bank financials, branch locations, institution search, IBAN validation, Indian IFSC lookup |
Expand Down
22 changes: 22 additions & 0 deletions config/tool_provider_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2420,6 +2420,28 @@ tools:
price_usd: "0.002"
cache_ttl: 60

# --- Xquik (X/Twitter Data) ---
- tool_id: xquik.search_tweets
name: Search X Tweets
provider: xquik
price_usd: "0.002"
cache_ttl: 60
- tool_id: xquik.user
name: X User Profile
provider: xquik
price_usd: "0.002"
cache_ttl: 300
- tool_id: xquik.followers
name: X User Followers
provider: xquik
price_usd: "0.003"
cache_ttl: 300
- tool_id: xquik.trends
name: X Trending Topics
provider: xquik
price_usd: "0.002"
cache_ttl: 60

# --- UC-210: Currents API (Global News) ---
- tool_id: currents.latest
name: Latest Global News
Expand Down
6 changes: 6 additions & 0 deletions src/adapters/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ import { WhoAdapter } from './who';
import { GdacsAdapter } from './gdacs';
import { RateApiAdapter } from './rateapi';
import { TwitterApiAdapter } from './twitterapi';
import { XquikAdapter } from './xquik';
import { CurrentsAdapter } from './currents';
import { IbanApiAdapter } from './ibanapi';
import { PubchemAdapter } from './pubchem';
Expand Down Expand Up @@ -791,6 +792,11 @@ export function resolveAdapter(toolId: string): BaseAdapter | undefined {
if (!twKey) return undefined;
return getOrCreate('twitterapi', () => new TwitterApiAdapter(twKey));
}
case 'xquik': {
const xquikKey = (config as Record<string, unknown>).PROVIDER_KEY_XQUIK as string | undefined;
if (!xquikKey) return undefined;
return getOrCreate('xquik', () => new XquikAdapter(xquikKey));
}
case 'pubchem': {
const ncbiKey = ((config as Record<string, unknown>).PROVIDER_KEY_NCBI as string) || '';
return getOrCreate('pubchem', () => new PubchemAdapter(ncbiKey));
Expand Down
186 changes: 186 additions & 0 deletions src/adapters/xquik/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { BaseAdapter } from '../base.adapter';
import {
type ProviderRawResponse,
type ProviderRequest,
ProviderErrorCode,
} from '../../types/provider';

/**
* Xquik adapter.
*
* Supported tools:
* xquik.search_tweets -> GET /api/v1/x/tweets/search
* xquik.user -> GET /api/v1/x/users/{id}
* xquik.followers -> GET /api/v1/x/users/{id}/followers
* xquik.trends -> GET /api/v1/x/trends
*
* Auth: x-api-key header.
*/
export class XquikAdapter extends BaseAdapter {
private readonly apiKey: string;

constructor(apiKey: string) {
super({
provider: 'xquik',
baseUrl: 'https://xquik.com/api/v1',
});
this.apiKey = apiKey;
}

protected buildRequest(req: ProviderRequest): {
url: string;
method: string;
headers: Record<string, string>;
} {
const params = req.params as Record<string, unknown>;
const headers: Record<string, string> = {
Accept: 'application/json',
'x-api-key': this.apiKey,
};

switch (req.toolId) {
case 'xquik.search_tweets': {
const qs = new URLSearchParams();
qs.set('q', String(params.query ?? 'news'));
qs.set('queryType', params.sort_order === 'top' ? 'Top' : 'Latest');
if (params.cursor) qs.set('cursor', String(params.cursor));
if (params.since_time) qs.set('sinceTime', String(params.since_time));
if (params.until_time) qs.set('untilTime', String(params.until_time));
if (params.limit) qs.set('limit', String(params.limit));
return {
url: `${this.baseUrl}/x/tweets/search?${qs.toString()}`,
method: 'GET',
headers,
};
}

case 'xquik.user': {
const userId = this.getUserId(params);
return {
url: `${this.baseUrl}/x/users/${encodeURIComponent(userId)}`,
method: 'GET',
headers,
};
}

case 'xquik.followers': {
const qs = new URLSearchParams();
const userId = this.getUserId(params);
if (params.cursor) qs.set('cursor', String(params.cursor));
if (params.page_size) qs.set('pageSize', String(params.page_size));
const suffix = qs.toString();
return {
url: `${this.baseUrl}/x/users/${encodeURIComponent(userId)}/followers${suffix ? `?${suffix}` : ''}`,
method: 'GET',
headers,
};
}

case 'xquik.trends': {
const qs = new URLSearchParams();
qs.set('woeid', String(params.woeid ?? 1));
if (params.count) qs.set('count', String(params.count));
return {
url: `${this.baseUrl}/x/trends?${qs.toString()}`,
method: 'GET',
headers,
};
}

default:
throw {
code: ProviderErrorCode.INVALID_RESPONSE,
httpStatus: 502,
message: `Unsupported tool: ${req.toolId}`,
provider: this.provider,
toolId: req.toolId,
durationMs: 0,
};
}
}

protected parseResponse(raw: ProviderRawResponse, req: ProviderRequest): unknown {
const body = raw.body as Record<string, unknown>;

switch (req.toolId) {
case 'xquik.search_tweets': {
const tweets = (body.tweets as Array<Record<string, unknown>>) ?? [];
return {
total: tweets.length,
has_next: body.has_next_page ?? false,
next_cursor: body.next_cursor ?? null,
tweets: tweets.map((tweet) => this.mapTweet(tweet)),
};
}

case 'xquik.user':
return this.mapUser(body);

case 'xquik.followers': {
const users = (body.users as Array<Record<string, unknown>>) ?? [];
return {
total: users.length,
has_next: body.has_next_page ?? false,
next_cursor: body.next_cursor ?? null,
followers: users.map((user) => this.mapUser(user)),
};
}

case 'xquik.trends': {
const trends = (body.trends as Array<Record<string, unknown>>) ?? [];
return {
total: body.count ?? trends.length,
woeid: body.woeid,
trends: trends.map((trend) => ({
name: trend.name,
description: trend.description,
query: trend.query,
rank: trend.rank,
})),
};
}

default:
return body;
}
}

private getUserId(params: Record<string, unknown>): string {
return String(params.username ?? params.user_id ?? '');
}

private mapTweet(tweet: Record<string, unknown>): Record<string, unknown> {
const author = tweet.author as Record<string, unknown> | undefined;
return {
id: tweet.id,
text: tweet.text,
created_at: tweet.createdAt,
author: author ? this.mapUser(author) : null,
likes: tweet.likeCount,
retweets: tweet.retweetCount,
replies: tweet.replyCount,
quotes: tweet.quoteCount,
views: tweet.viewCount,
bookmarks: tweet.bookmarkCount,
lang: tweet.lang,
};
}

private mapUser(user: Record<string, unknown>): Record<string, unknown> {
return {
id: user.id,
username: user.username,
name: user.name,
bio: user.description,
location: user.location,
followers: user.followers,
following: user.following,
tweets_count: user.statusesCount,
verified: user.verified,
verified_type: user.verifiedType,
profile_image: user.profilePicture,
profile_banner: user.coverPicture,
created_at: user.createdAt,
};
}
}
3 changes: 3 additions & 0 deletions src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ export const appEnvSchema = z.object({
// TwitterAPI.io (UC-198) — Twitter/X data, pay-per-call
PROVIDER_KEY_TWITTERAPI: z.string().optional().default(''),

// Xquik - X/Twitter data API
PROVIDER_KEY_XQUIK: z.string().optional().default(''),

// Currents API (UC-210) — global news 70+ countries
PROVIDER_KEY_CURRENTS: z.string().optional().default(''),

Expand Down
38 changes: 38 additions & 0 deletions src/mcp/tool-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4071,6 +4071,44 @@ export const TOOL_DEFINITIONS: McpToolDefinition[] = [
annotations: READ_ONLY,
},

// Xquik (4)
{
toolId: 'xquik.search_tweets',
mcpName: 'xquik.tweets.search',
title: 'Search X Tweets with Xquik',
description:
'Search X tweets with X query operators, cursor pagination, optional time bounds, and engagement-ranked or chronological sort. Returns tweet text, author, metrics, timestamps, and pagination cursors.',
category: 'social',
annotations: READ_ONLY,
},
{
toolId: 'xquik.user',
mcpName: 'xquik.users.profile',
title: 'X User Profile with Xquik',
description:
'Look up an X user profile by username or user ID. Returns display name, bio, follower and following counts, verification status, profile images, location, and account creation date.',
category: 'social',
annotations: READ_ONLY,
},
{
toolId: 'xquik.followers',
mcpName: 'xquik.users.followers',
title: 'X User Followers with Xquik',
description:
'Get a paginated follower list for an X user by username or user ID. Returns profile details with cursor pagination and configurable page size.',
category: 'social',
annotations: READ_ONLY,
},
{
toolId: 'xquik.trends',
mcpName: 'xquik.trends.regional',
title: 'X Trending Topics with Xquik',
description:
'Get current X trending topics by WOEID region. Returns trend names, optional descriptions, search queries, rank, count, and the region used.',
category: 'social',
annotations: READ_ONLY,
},

// Currents API (3) — UC-210
{
toolId: 'currents.latest',
Expand Down
2 changes: 2 additions & 0 deletions src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ import { whoSchemas } from './who.schema';
import { gdacsSchemas } from './gdacs.schema';
import { rateapiSchemas } from './rateapi.schema';
import { twitterapiSchemas } from './twitterapi.schema';
import { xquikSchemas } from './xquik.schema';
import { currentsSchemas } from './currents.schema';
import { ibanapiSchemas } from './ibanapi.schema';
import { pubchemSchemas } from './pubchem.schema';
Expand Down Expand Up @@ -303,6 +304,7 @@ export const toolSchemas: Record<string, ZodSchema> = {
...gdacsSchemas,
...rateapiSchemas,
...twitterapiSchemas,
...xquikSchemas,
...currentsSchemas,
...ibanapiSchemas,
...pubchemSchemas,
Expand Down
Loading