Install
$ agentstack add mcp-xpozpublic-xpoz-python-sdk ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Xpoz Python SDK
[](https://pypi.org/project/xpoz/)
Python SDK for the Xpoz social media intelligence platform. Query Twitter/X, Instagram, Reddit, and TikTok data through a simple, Pythonic interface.
Installation
pip install xpoz
Requires Python 3.10+.
Get an API Key
Sign up and get your token at https://xpoz.ai/get-token.
Once you have it, pass it directly or set the XPOZ_API_KEY environment variable:
export XPOZ_API_KEY=your-token-here
What is Xpoz?
Xpoz provides unified access to social media data across Twitter/X, Instagram, Reddit, and TikTok. The platform indexes billions of posts, user profiles, and engagement metrics — making it possible to search, analyze, and export social media data at scale.
The SDK wraps Xpoz's MCP server, abstracting away transport, authentication, operation polling, and pagination into a clean developer-friendly API.
Features
- 42 data methods across Twitter, Instagram, Reddit, and TikTok
- Sync and async clients —
XpozClientandAsyncXpozClient - Automatic operation polling — long-running queries are abstracted away
- Response modes —
ResponseType.FASTfor quick limited results,PAGINGfor full pagination,CSVfor export - Server-side pagination —
PaginatedResultwithnext_page(),get_page(n) - CSV export —
export_csv()on any paginated result - Field selection — request only the fields you need in Pythonic snake_case
- Pydantic v2 models — fully typed results with autocomplete support
- Namespaced API —
client.twitter.*,client.instagram.*,client.reddit.*,client.tiktok.*
Quick Start
from xpoz import XpozClient
client = XpozClient("your-api-key")
user = client.twitter.get_user("elonmusk")
print(f"{user.name} — {user.followers_count:,} followers")
results = client.twitter.search_posts("artificial intelligence", start_date="2025-01-01")
for tweet in results.data:
print(tweet.text, tweet.like_count)
client.close()
Authentication
Get your API key at https://xpoz.ai/get-token, then use it as follows:
# Pass API key directly
client = XpozClient("your-api-key")
# Or use XPOZ_API_KEY environment variable
import os
os.environ["XPOZ_API_KEY"] = "your-api-key"
client = XpozClient()
# Custom server URL (also reads XPOZ_SERVER_URL env var)
client = XpozClient("your-api-key", server_url="https://xpoz.ai/mcp")
# Custom operation timeout (default: 300 seconds)
client = XpozClient("your-api-key", timeout=600)
Trial Access (No Sign-Up Required)
Want to try the SDK before signing up? Mint a free trial token (no account needed, valid for 5 days):
curl -X POST https://api.xpoz.ai/api/trial/token \
-H "Content-Type: application/json" \
-d '{"source": "sdk"}'
# -> { "success": true, "data": { "accessKey": "TRIAL...", "expiresInSeconds": 432000 }, ... }
The source field is required — it identifies where the trial token request came from (e.g. skills, a specific page, sdk, cli).
Then use the returned token (it starts with TRIAL) as your API key:
# Optional: try without your own account
client = XpozClient("TRIAL...") # the token from the curl response above
user = client.twitter.get_user("elonmusk")
The trial token is rate-limited and intentionally restricted:
- Read-only data tools only — search and lookup methods across Twitter, Instagram, Reddit, and TikTok. Account, tracking, and operation-management methods are not available and return an upgrade prompt.
- Up to 5 results per call — every response is capped at 5 items.
response_typeis forced tofast, so pagination (PAGING) and CSV export (CSV) are unavailable. - Cached data only — trial reads from the database and does not trigger live on-demand crawling, so the very latest posts may not appear.
For full result limits, pagination, CSV export, and live data, get your own API key.
Context Manager
# Sync — auto-closes on exit
with XpozClient("your-api-key") as client:
user = client.twitter.get_user("elonmusk")
# Async
import asyncio
from xpoz import AsyncXpozClient
async def main():
async with AsyncXpozClient("your-api-key") as client:
user = await client.twitter.get_user("elonmusk")
results = await client.twitter.search_posts("AI")
page2 = await results.next_page()
asyncio.run(main())
Pagination
Methods that return large datasets use server-side pagination (100 items per page). These return a PaginatedResult[T] with built-in helpers:
results = client.twitter.search_posts("AI")
results.data # list[TwitterPost] — current page
results.pagination.total_rows # total matching rows
results.pagination.total_pages # total pages
results.pagination.page_number # current page number
results.pagination.page_size # items per page (100)
results.pagination.results_count # items on current page
results.has_next_page() # bool
# Navigate pages
page2 = results.next_page() # fetch next page
page5 = results.get_page(5) # jump to specific page
# Export to CSV
csv_url = results.export_csv() # returns download URL
Response Modes
Methods that return PaginatedResult support a response_type parameter to control how results are fetched. Import the ResponseType enum:
from xpoz import XpozClient, ResponseType
Fast mode (default)
Returns up to limit results directly — no polling, no pagination. This is the default behavior when response_type is not specified.
results = client.twitter.search_posts(
"bitcoin",
limit=10,
fields=["id", "text", "like_count"]
)
# Equivalent to response_type=ResponseType.FAST
for tweet in results.data:
print(tweet.text)
Paging mode
Returns full paginated results (100 items per page). Use this when you need to iterate through all results.
results = client.twitter.search_posts(
"bitcoin",
response_type=ResponseType.PAGING,
)
CSV mode
Triggers a server-side CSV export. The result contains no inline data — call export_csv() to get the download URL.
results = client.twitter.search_posts(
"bitcoin",
response_type=ResponseType.CSV,
)
csv_url = results.export_csv()
Supported methods
response_type and limit are available on:
| Platform | Method | | --------- | ----------------------- | | Twitter | search_posts | | Twitter | get_posts_by_author | | Twitter | get_users_by_keywords | | Instagram | search_posts | | Instagram | get_posts_by_user | | Instagram | get_users_by_keywords | | Reddit | search_posts | | TikTok | search_posts | | TikTok | get_posts_by_user | | TikTok | get_users_by_keywords | | TikTok | get_posts_by_hashtags | | TikTok | get_users_by_hashtags | | TikTok | get_posts_by_sound |
Field Selection
All methods accept a fields parameter. Use snake_case — the SDK translates to camelCase automatically.
# Only fetch the fields you need (faster + less memory)
results = client.twitter.search_posts(
"AI",
fields=["id", "text", "like_count", "retweet_count", "created_at_date"]
)
user = client.twitter.get_user(
"elonmusk",
fields=["id", "username", "name", "followers_count", "description"]
)
Requesting fewer fields significantly improves response time.
Query Syntax
The query parameter on all search_* and get_*_by_keywords methods supports a Lucene-style full-text syntax across Twitter, Instagram, and Reddit.
Exact phrase
Wrap in double quotes to require an exact match:
"machine learning"
"climate change"
Keywords (any word)
Space-separated terms without quotes match posts containing any of the words:
AI crypto blockchain
Boolean operators
Use AND, OR, NOT (case-insensitive). A bare space is treated as OR — be explicit:
"deep learning" AND python
tensorflow OR pytorch
climate NOT politics
Grouping with parentheses
(AI OR "artificial intelligence") AND ethics
(startup OR entrepreneur) NOT "venture capital"
Combined example
results = client.twitter.search_posts(
'("machine learning" OR "deep learning") AND python NOT spam',
start_date="2025-01-01",
language="en",
)
> Note: Do not use from:, lang:, since:, or until: in the query string — use the dedicated parameters (author_username, language, start_date, end_date) instead.
Error Handling
from xpoz import (
XpozError,
AuthenticationError,
ConnectionError,
OperationTimeoutError,
OperationFailedError,
OperationCancelledError,
NotFoundError,
ValidationError,
)
try:
user = client.twitter.get_user("nonexistent_user_12345")
except OperationFailedError as e:
print(f"Operation {e.operation_id} failed: {e.error}")
except OperationTimeoutError as e:
print(f"Timed out after {e.elapsed_seconds}s")
except AuthenticationError:
print("Invalid API key")
except XpozError as e:
print(f"Xpoz error: {e}")
API Reference
Twitter — client.twitter
get_user(identifier, identifier_type="username", *, fields) -> TwitterUser
Get a single Twitter user profile.
# By username (default)
user = client.twitter.get_user("elonmusk")
# By numeric ID
user = client.twitter.get_user("44196397", identifier_type="id")
search_users(name, *, limit=None, fields) -> list[TwitterUser]
Search users by name or username. Returns up to 10 results.
users = client.twitter.search_users("elon")
get_user_connections(username, connection_type, *, fields, force_latest) -> PaginatedResult[TwitterUser]
Get followers or following for a user.
followers = client.twitter.get_user_connections("elonmusk", "followers")
following = client.twitter.get_user_connections("elonmusk", "following")
get_users_by_keywords(query, *, fields, start_date, end_date, language, force_latest, response_type, limit) -> PaginatedResult[TwitterUser]
Find users who authored posts matching a keyword query. Includes aggregation fields like relevant_tweets_count, relevant_tweets_likes_sum.
users = client.twitter.get_users_by_keywords(
'"machine learning"',
fields=["username", "name", "followers_count", "relevant_tweets_count", "relevant_tweets_likes_sum"]
)
get_posts_by_ids(post_ids, *, fields, force_latest) -> list[TwitterPost]
Get 1-100 posts by their IDs.
tweets = client.twitter.get_posts_by_ids(["1234567890", "0987654321"])
get_posts_by_author(identifier, identifier_type="username", *, fields, start_date, end_date, force_latest, response_type, limit) -> PaginatedResult[TwitterPost]
Get all posts by an author with optional date filtering.
results = client.twitter.get_posts_by_author("elonmusk", start_date="2025-01-01")
search_posts(query, *, fields, start_date, end_date, author_username, author_id, language, force_latest, response_type, limit) -> PaginatedResult[TwitterPost]
Full-text search with filters. Supports exact phrases ("machine learning"), boolean operators (AI AND python), and parentheses.
results = client.twitter.search_posts(
'"artificial intelligence" AND ethics',
start_date="2025-01-01",
end_date="2025-06-01",
language="en",
fields=["id", "text", "like_count", "author_username", "created_at_date"]
)
get_retweets(post_id, *, fields, start_date) -> PaginatedResult[TwitterPost]
Get retweets of a specific post (database only).
retweets = client.twitter.get_retweets("1234567890")
get_quotes(post_id, *, fields, start_date, force_latest) -> PaginatedResult[TwitterPost]
Get quote tweets of a specific post.
quotes = client.twitter.get_quotes("1234567890")
get_comments(post_id, *, fields, start_date, force_latest) -> PaginatedResult[TwitterPost]
Get replies to a specific post.
comments = client.twitter.get_comments("1234567890")
get_post_interacting_users(post_id, interaction_type, *, fields, force_latest) -> PaginatedResult[TwitterUser]
Get users who interacted with a post. interaction_type: "commenters", "quoters", "retweeters".
commenters = client.twitter.get_post_interacting_users("1234567890", "commenters")
count_posts(phrase, *, start_date, end_date) -> int
Count tweets containing a phrase within a date range.
count = client.twitter.count_posts("bitcoin", start_date="2025-01-01")
print(f"{count:,} tweets mention bitcoin")
Instagram — client.instagram
get_user(identifier, identifier_type="username", *, fields) -> InstagramUser
user = client.instagram.get_user("instagram")
print(f"{user.full_name} — {user.follower_count:,} followers")
search_users(name, *, limit=None, fields) -> list[InstagramUser]
users = client.instagram.search_users("nasa")
get_user_connections(username, connection_type, *, fields, force_latest) -> PaginatedResult[InstagramUser]
followers = client.instagram.get_user_connections("instagram", "followers")
get_users_by_keywords(query, *, fields, start_date, end_date, force_latest, response_type, limit) -> PaginatedResult[InstagramUser]
users = client.instagram.get_users_by_keywords('"sustainable fashion"')
get_posts_by_ids(post_ids, *, fields, force_latest) -> list[InstagramPost]
Post IDs must be in strong_id format: "media_id_user_id" (e.g. "3606450040306139062_4836333238").
posts = client.instagram.get_posts_by_ids(["3606450040306139062_4836333238"])
get_posts_by_user(identifier, identifier_type="username", *, fields, start_date, end_date, force_latest, response_type, limit) -> PaginatedResult[InstagramPost]
results = client.instagram.get_posts_by_user("nasa")
search_posts(query, *, fields, start_date, end_date, force_latest, response_type, limit) -> PaginatedResult[InstagramPost]
results = client.instagram.search_posts("travel photography")
get_comments(post_id, *, fields, start_date, end_date, force_latest) -> PaginatedResult[InstagramComment]
comments = client.instagram.get_comments("3606450040306139062_4836333238")
get_post_interacting_users(post_id, interaction_type, *, fields, force_latest) -> PaginatedResult[InstagramUser]
interaction_type: "commenters", "likers".
likers = client.instagram.get_post_interacting_users("3606450040306139062_4836333238", "likers")
Reddit — client.reddit
get_user(username, *, fields) -> RedditUser
user = client.reddit.get_user("spez")
print(f"{user.username} — {user.total_karma:,} karma")
search_users(name, *, limit=None, fields) -> list[RedditUser]
users = client.reddit.search_users("spez")
get_users_by_keywords(query, *, fields, start_date, end_date, subreddit, force_latest) -> PaginatedResult[RedditUser]
users = client.reddit.get_users_by_keywords('"machine learning"', subreddit="MachineLearning")
search_posts(query, *, fields, start_date, end_date, sort, time, subreddit, force_latest, response_type, limit) -> PaginatedResult[RedditPost]
sort: "relevance", "hot", "top", "new", "comments". time: "hour", "day", "week", "month", "year", "all".
results = client.reddit.search_posts(
"python tutorial",
subreddit="learnpython",
sort="top",
time="month"
)
`getpostwithcomments(postid, *, postfields, commentfields, force_latest) -> RedditPost
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: XPOZpublic
- Source: XPOZpublic/xpoz-python-sdk
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.