Xanguard API Docs
Build on top of the fastest Twitter monitoring engine available. Detect tweets in real-time with sub-second latency and deliver them to your app, bot, or trading system through the channel that fits your stack.
Xanguard APIs
All Xanguard APIs share one host — https://api.xanguard.tech — speak JSON, and wrap every response in the same envelope: {"ok":true,"data":…} on success, {"ok":false,"error":"…"} on failure. Each product lives under its own base path and issues keys with its own prefix:
| API | Base path | Key prefix | Issued by | Purpose |
|---|---|---|---|---|
| Tweet Alerts (consumer) | /v1 |
xg_ |
@Xanguard_bot /apikey |
Track accounts, settings, webhooks, WS alerts |
| B2B Monitoring | /v1/dt |
dt_ |
@B2B_Xanguard_bot /apikey |
Handles, profile/follow data, realtime WS |
| CA Search | /v1/search |
dt_ |
B2B add-on (Extra Features menu) | Tweet search by CA/ticker/keyword |
| Community Watch | /v1/cw |
cw_ |
@F_xanguard_bot | Community events |
| Convergence Tracker | /v1/ct |
ct_ |
@T_xanguard_bot | Community convergence |
| ECA | /v1/eca |
eca_ |
@Xanguard_bot | pump.fun launch watchlist |
| Engagement Tracker | /v1/et |
et_ |
@E_Xanguard_bot | Per-tweet engagement |
| Trending Alerts | /v1/trending |
trend_ |
@Trends_Xanguard_bot | Trending feed |
| PumpFun Livestream | /v1/pf |
pf_ |
@PF_Xanguard_bot | Livestream start/stop |
| Search Alerts | /v1/sa |
sa_ |
@Xanguard_bot | Keyword search alerts |
WebSocket auth
Consumer and product WebSockets authenticate with an ?api_key= query parameter (e.g. wss://api.xanguard.tech/v1/ws?api_key=xg_your_key). The B2B realtime WebSocket is the exception: it authenticates with a LOGIN opcode after connecting — see B2B Realtime WebSocket.
Keys are product-scoped. A dt_ key won't work on /v1/cw, a cw_ key won't work on /v1/et, and so on. Generate a key from the bot that owns the product you want to use.
Looking for bot setup and user guides instead? See the Telegram guides.
Conventions
Behavior shared by every Xanguard API, collected in one place.
Response Envelope
Every REST response is wrapped in a standard envelope. On success, ok is true and the payload is in data. On error, ok is false and the message is in error.
{
"ok": true,
"data": { ... }
}
{
"ok": false,
"error": "Invalid API key"
}Authentication
All REST APIs authenticate with a Bearer token in the Authorization header:
Authorization: Bearer <prefix>_your_api_key_here
Each product issues keys with its own prefix (xg_, dt_, cw_, …) — see the API overview table for the full list and issuing bots. Keys are product-scoped. CA Search additionally accepts the twitterapi.io-compatible X-API-Key header.
Error Codes
Common HTTP status codes across the APIs:
| Status | Meaning |
|---|---|
400 | Bad request — missing or invalid field |
401 | Authentication failed — missing, malformed, or invalid API key |
403 | Not allowed — plan limit reached, feature not enabled on this key, or Free-tier key |
404 | Resource not found (or no data collected yet) |
409 | Conflict — resource already exists |
429 | Rate limit or daily allowance exhausted — back off and retry |
500 | Internal or upstream failure — retry |
503 | Service temporarily unavailable — retry with backoff |
B2B Monitoring and CA Search document per-endpoint error tables in their own sections: B2B API and CA Search.
Pagination
Two conventions exist. B2B list endpoints paginate with limit/offset query params (e.g. /v1/dt/followers/{handle}). CA Search uses an opaque cursor: pass the previous response's next_cursor as cursor to continue a truncated result set. Consumer API lists are unpaginated and return the full set.
Rate Limits
| Surface | Limit |
|---|---|
Consumer REST (/v1) | Per-key sliding window that scales with your tier; excess returns 429 |
B2B REST (/v1/dt) | Not per-second rate-limited — 64 KB request-body cap; 5 concurrent WebSocket connections per key |
CA Search (/v1/search) | 10 requests/sec per key + daily plan allowance |
| WebSockets (all) | 10 inbound messages/sec per connection |
Webhooks
Webhook deliveries are signed POST requests with a JSON body. Every delivery includes an X-Signature header containing a lowercase HMAC-SHA256 hex digest of the raw request body, computed using your webhook secret (returned once at registration). Always verify this signature before processing the payload.
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
import hmac, hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Retries: if your endpoint returns a non-2xx status code or the request times out, Xanguard makes up to 3 delivery attempts with backoff (1s, then 2s between retries). After 10 consecutive failures across any deliveries, the webhook is automatically disabled — delete it and register a new one (new id + new secret) once your endpoint is healthy again.
Community Watch deliveries use the same signing scheme.
Quick Start
Consumer: Tweet Alerts
Track Twitter/X accounts and receive tweet alerts in your app — four steps:
- Open @Xanguard_bot, send
/start, and choose a plan. - Send
/apikeyto get yourxg_key. Base URL ishttps://api.xanguard.tech/v1. - Add a handle:
POST /v1/accountswith body{"handles":["elonmusk"]}. - Receive alerts on the WebSocket (
?api_key=auth) or via a signed webhook.
B2B: Handle Monitoring
Xanguard is an API-first, real-time Twitter/X firehose. Get from zero to a live event stream in four steps.
Onboard
Open @B2B_Xanguard_bot on Telegram, send /start, and choose a plan (priced by handle count — see B2B Pricing).
Get your API key
Send /apikey to receive a key with the dt_ prefix. Base URL is https://api.xanguard.tech/v1/dt. Authenticate every REST call with a Bearer header:
Authorization: Bearer dt_your_api_key_hereAdd a handle
Register an account to monitor. Every response uses the envelope {"ok":true,"data":…} (or {"ok":false,"error":"…"} on failure).
curl -X POST https://api.xanguard.tech/v1/dt/targets \
-H "Authorization: Bearer dt_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"handle":"elonmusk"}'
# → 201 {"ok":true,"data":{"handle":"elonmusk","twitter_user_id":"44196397"}}Stream events
Connect the WebSocket, send the LOGIN opcode with your dt_ key, and receive real-time events for every monitored handle. See B2B Realtime WebSocket for the full protocol.
wss://api.xanguard.tech/v1/dt/realtime/wsPrefer chat delivery, or looking for the consumer Tweet-Alerts bot? See the Telegram bot guide.
REST API
The REST API exposes 15 endpoints for managing your Xanguard account programmatically. All endpoints live under a single base URL and return consistent JSON responses.
https://api.xanguard.tech/v1
Authentication
All API requests require a Bearer token in the Authorization header. Consumer API keys start with xg_ and are generated via /apikey in @Xanguard_bot. (B2B keys start with dt_ and come from @B2B_Xanguard_bot — they're separate products.) API access requires a paid plan — Free-tier keys get 403.
Authorization: Bearer xg_your_api_key_here
Response Envelope
Every response is wrapped in a standard envelope. On success, the ok field is true and the payload is in data. On error, ok is false and the error message is in error.
{
"ok": true,
"data": { ... }
}
{
"ok": false,
"error": "Invalid API key"
}
Rate Limiting
Requests are rate-limited per key using a sliding window; the limit scales with your subscription tier. Exceeding it returns 429 Too Many Requests — back off and retry.
Accounts
Manage your tracked Twitter accounts. Add, remove, configure keywords, and mute/unmute handles.
| Method | Path | Description |
|---|---|---|
| GET | /v1/accounts |
List all tracked accounts |
| POST | /v1/accounts |
Add accounts (max 25 per request) |
| GET | /v1/accounts/{handle} |
Get account detail + profile data |
| DELETE | /v1/accounts/{handle} |
Remove an account |
| PUT | /v1/accounts/{handle}/keywords |
Set keyword filters (max 20) |
| DELETE | /v1/accounts/{handle}/keywords |
Clear all keywords |
| PUT | /v1/accounts/{handle}/mute |
Mute or unmute an account |
| PATCH | /v1/accounts/{handle}/filters |
Set per-account notification filters (exclude replies/reposts, contracts-only, etc.) |
Returns all Twitter accounts you are currently monitoring, along with their keyword filters and mute status.
Response
{
"ok": true,
"data": {
"accounts": [
{
"handle": "elonmusk",
"keywords": [],
"muted": false,
"is_active": true,
"exclude_replies": false,
"exclude_reposts": false,
"exclude_quotes": false,
"added_at": 1234567890
}
],
"count": 1,
"limit": 10
}
}
Add one or more Twitter handles to your monitoring list. Maximum 25 handles per request. Handles are case-insensitive and the @ prefix is optional.
Request Body
{
"handles": ["elonmusk", "VitalikButerin"]
}
Response
{
"ok": true,
"data": {
"added": ["elonmusk"],
"already_exists": ["vitalikbuterin"],
"total": 5,
"limit": 10
}
}
Get detailed information about a single tracked account, including profile data fetched from Twitter (display name, follower count, verification status, and profile picture).
Response
{
"ok": true,
"data": {
"handle": "elonmusk",
"keywords": ["bitcoin", "doge"],
"muted": false,
"is_active": true,
"exclude_replies": false,
"exclude_reposts": false,
"exclude_quotes": false,
"added_at": 1234567890,
"profile": {
"display_name": "Elon Musk",
"followers": 180000000,
"is_verified": true,
"profile_pic": "https://pbs.twimg.com/..."
}
}
}
Remove a Twitter handle from your monitoring list. This also removes any keyword filters associated with the handle.
Response
{
"ok": true,
"data": {
"removed": true,
"handle": "elonmusk"
}
}
Set keyword filters for a specific account. Only tweets containing at least one of the specified keywords will trigger an alert. Maximum 20 keywords. This replaces any existing keywords.
Request Body
{
"keywords": ["bitcoin", "solana", "launch"]
}
Response
{
"ok": true,
"data": {
"handle": "elonmusk",
"keywords": ["bitcoin", "solana", "launch"]
}
}
Clear all keyword filters for a specific account. After clearing, all tweets from this account will trigger alerts (subject to global settings).
Response
{
"ok": true,
"data": {
"handle": "elonmusk",
"keywords": []
}
}
Mute or unmute a tracked account. Muted accounts remain in your list but do not trigger any notifications.
Request Body
{
"muted": true
}
Response
{
"ok": true,
"data": {
"handle": "elonmusk",
"muted": true
}
}
Settings
Manage your global notification preferences. These settings apply to all delivery channels.
| Method | Path | Description |
|---|---|---|
| GET | /v1/settings |
Get current notification preferences |
| PATCH | /v1/settings |
Update preferences (partial update) |
Settings Fields
All fields are booleans. The PATCH endpoint accepts partial updates — only include the fields you want to change.
Returns your current notification preferences.
Response
{
"ok": true,
"data": {
"exclude_replies": false,
"contracts_only": false,
"notifications_paused": false,
"exclude_reposts": false,
"exclude_quotes": false,
"auto_topics": true,
"contract_topic": false
}
}
Update one or more notification settings. Only include the fields you want to change. Omitted fields remain unchanged.
Request Body
{
"exclude_replies": true,
"contracts_only": true
}
Response
Returns the full settings object after the update.
{
"ok": true,
"data": {
"exclude_replies": true,
"contracts_only": true,
"notifications_paused": false,
"exclude_reposts": false,
"exclude_quotes": false,
"auto_topics": true,
"contract_topic": false
}
}
Subscription
View your current subscription tier and browse available plans.
| Method | Path | Description |
|---|---|---|
| GET | /v1/subscription |
Current tier, limits, and expiry |
| GET | /v1/plans |
List all available plans |
Returns your current subscription tier, account limit, and expiration date.
Response
{
"ok": true,
"data": {
"tier": "starter",
"account_limit": 10,
"expires_at": "2026-03-21T00:00:00Z"
}
}
Returns all available subscription plans with their prices, account limits, and webhook limits.
Response
{
"ok": true,
"data": {
"plans": [
{
"name": "Starter",
"display_name": "Starter",
"price_usd": 19,
"account_limit": 10,
"max_webhooks": 1,
"duration_hours": 720
}
]
}
}
The Free plan is not included in this list.
Webhooks
Register HTTPS endpoints to receive tweet notifications via signed POST requests. The number of webhooks you can register depends on your subscription tier.
| Method | Path | Description |
|---|---|---|
| POST | /v1/webhooks |
Register a new webhook |
| GET | /v1/webhooks |
List active webhooks |
| DELETE | /v1/webhooks/{id} |
Deactivate a webhook |
Register a new webhook endpoint (http or https — HTTPS recommended, since payloads travel signed but unencrypted). On success, the response includes a one-time secret field containing the HMAC-SHA256 signing key. Save this immediately — it is never shown again.
Request Body
{
"url": "https://your-server.com/webhook",
"events": ["tweet"],
"filter_handles": [],
"filter_keywords": []
}
Tip: Leave filter_handles empty to receive tweets from all your tracked accounts. Leave filter_keywords empty to receive all tweets without keyword filtering.
Response
{
"ok": true,
"data": {
"id": 42,
"url": "https://your-server.com/webhook",
"events": ["tweet"],
"filter_handles": [],
"filter_keywords": [],
"is_active": true,
"consecutive_failures": 0,
"created_at": "2026-07-21T12:00:00Z",
"secret": "9f2c…(64 hex chars)…b81a"
}
}
Important: The secret field is only returned once, at creation time. Store it securely. You will need it to verify webhook signatures.
List all your registered webhooks. The secret is not included in list responses.
Response
{
"ok": true,
"data": {
"webhooks": [
{
"id": 42,
"url": "https://your-server.com/webhook",
"events": ["tweet"],
"filter_handles": [],
"filter_keywords": [],
"is_active": true,
"consecutive_failures": 0,
"created_at": "2026-07-21T12:00:00Z"
}
],
"count": 1,
"limit": 5
}
}
Deactivate a webhook. It will stop receiving deliveries immediately.
Response
{
"ok": true,
"data": {
"deleted": true,
"id": 42
}
}
Webhook Delivery
When a tweet matches your filters, Xanguard sends a POST request to your registered URL with a JSON body containing the tweet data.
Signature Verification
Every delivery includes an X-Signature header containing a lowercase HMAC-SHA256 hex digest of the raw request body, computed using your webhook secret. Always verify this signature before processing the payload.
Verification snippets in JavaScript and Python live under Conventions → Webhooks.
Retry Policy
If your endpoint returns a non-2xx status code or the request times out, Xanguard makes up to 3 delivery attempts with backoff (1s, then 2s between retries). After 10 consecutive failures across any deliveries, the webhook is automatically disabled — delete it and register a new one (new id + new secret) once your endpoint is healthy again.
WebSocket
The WebSocket endpoint provides a persistent, real-time stream of tweet alerts. Connect once, subscribe to handles on the fly, and receive structured JSON messages as tweets happen. This is ideal for trading bots, dashboards, and any application that needs the lowest possible latency.
Connection
Connect with your API key as a query parameter:
wss://api.xanguard.tech/v1/ws?api_key=xg_your_key
Client to Server Messages
After connecting, send JSON messages to subscribe or unsubscribe from handles:
{
"type": "subscribe",
"handles": ["elonmusk", "VitalikButerin"]
}
{
"type": "unsubscribe",
"handles": ["elonmusk"]
}
Server to Client Messages
Tweet Alert
Received when a tracked account posts a tweet:
{
"type": "alert",
"tweet_id": "1947000000000000000",
"handle": "elonmusk",
"text": "Just bought more $BTC",
"url": "https://twitter.com/elonmusk/status/1947000000000000000",
"image_url": null,
"image_urls": [],
"is_reply": false,
"is_quote": false,
"received_at": 1784646000120,
"created_at": 1784645999800,
"original_tweet_id": null,
"possibly_sensitive": false,
"mentions": []
}
received_at is when Xanguard detected the tweet; created_at is when Twitter says it was posted — the difference is your true detection latency. Quotes include an embedded quoted_tweet object (id, text, author); replies include in_reply_to_user / in_reply_to_tweet_id refs plus an embedded quoted_tweet carrying the hydrated parent tweet (id, text, author) — label by is_reply vs is_quote, not by quoted_tweet presence. Reply/quote context is hydrated inline before delivery (+60–90ms typical, 200ms cap, only on those events); plain tweets are unaffected. All timestamps are epoch milliseconds.
Acknowledgement
Sent after a successful subscribe or unsubscribe action:
{
"type": "ack",
"action": "subscribe",
"handles": ["elonmusk"],
"active": 1,
"max": 25
}
Error
Sent when a request cannot be fulfilled:
{
"type": "error",
"message": "Would exceed handle limit: 10 + 5 new = 15, max 10"
}
Limits
| Limit | Value |
|---|---|
| Connections | Per-plan concurrent connection cap — excess attempts are rejected with HTTP 429 |
| Inbound messages | 10 messages/sec per connection — sustained bursts force a disconnect |
| App-level ping | Send {"type":"ping"} to receive {"type":"pong"} (optional liveness check) |
Keepalive
The server sends a WebSocket ping frame every 30 seconds. Most WebSocket libraries answer automatically. If pongs go missing for ~3 minutes (6 consecutive pings), the server closes the connection. Your client should implement automatic reconnection with backoff.
Example: JavaScript Client
const ws = new WebSocket(
'wss://api.xanguard.tech/v1/ws?api_key=xg_your_key'
);
ws.onopen = () => {
// Subscribe to handles once connected
ws.send(JSON.stringify({
type: 'subscribe',
handles: ['elonmusk', 'VitalikButerin']
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'alert') {
console.log(`Tweet from @${msg.handle}: ${msg.text}`);
console.log(`Link: ${msg.url}`);
}
if (msg.type === 'ack') {
console.log(`Watching ${msg.active}/${msg.max} handles`);
}
if (msg.type === 'error') {
console.error(`Error: ${msg.message}`);
}
};
ws.onclose = () => {
// Implement reconnection with backoff
console.log('Disconnected, reconnecting...');
};
Example: Python Client
import asyncio, json, websockets
async def main():
uri = "wss://api.xanguard.tech/v1/ws?api_key=xg_your_key"
async with websockets.connect(uri) as ws:
# Subscribe to handles
await ws.send(json.dumps({
"type": "subscribe",
"handles": ["elonmusk", "VitalikButerin"]
}))
async for message in ws:
msg = json.loads(message)
if msg["type"] == "alert":
print(f"@{msg['handle']}: {msg['text']}")
print(f"Link: {msg['url']}")
asyncio.run(main())
Xanguard B2B
Xanguard B2B is a real-time Twitter/X monitoring API. It streams tweets, deleted-tweet alerts, follow/unfollow events, profile changes, and new follower detection for your tracked accounts via WebSocket and REST API. Managed via @B2B_Xanguard_bot.
Modules
| Module | Events |
|---|---|
| Realtime (tweets) | New tweets, replies, quotes, retweets |
| Deleted tweets | Alert when a tracked account deletes a tweet |
| Follows | Follow and unfollow detection |
| Profile Watch | Name, bio, avatar, follower count changes |
| Followers | New follower detection |
Bot Commands
| Command | Description |
|---|---|
/start | Dashboard & subscription |
/add @handle | Add handle to monitor |
/remove @handle | Remove handle |
/list | List all monitored handles |
/status | Subscription status |
/apikey | View or regenerate API key |
/help | Command reference |
Pricing
Three module tiers, priced by handle count (monthly):
| Handles | Starter tweets + deleted-tweet | Pro + profile + new-follower | Enterprise + follow/unfollow |
|---|---|---|---|
| 50 | $49/mo | $99/mo | $249/mo |
| 250 | $229/mo | $429/mo | $979/mo |
| 500 | $449/mo | $749/mo | $1,649/mo |
| 1000 | $849/mo | $1,349/mo | $2,849/mo |
B2B API
All B2B API requests require a Bearer token with dt_ prefix, generated via /apikey in the bot.
Authorization: Bearer dt_your_api_key_hereREST Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /v1/dt/targets | List monitored handles |
| POST | /v1/dt/targets | Add handle. Body: {"handle": "username"} |
| DELETE | /v1/dt/targets/{handle} | Remove handle |
| GET | /v1/dt/profile/{handle} | Latest profile snapshot |
| GET | /v1/dt/profile/{handle}/history | Profile change history |
| GET | /v1/dt/tweets/{handle} | Recent tweets |
| GET | /v1/dt/following/{handle} | Accounts the handle follows |
| GET | /v1/dt/followers/{handle} | The handle's followers |
| GET | /v1/dt/communities/{handle} | Communities the handle belongs to |
| GET | /v1/dt/social/diff/{handle} | Follow/unfollow diff over a trailing window |
| GET | /v1/dt/webhook | Get webhook URL |
| PUT | /v1/dt/webhook | Set webhook URL |
| GET | /v1/dt/status | Subscription status |
Every response uses the standard envelope: {"ok":true,"data":…} on success, {"ok":false,"error":"…"} on failure.
POST /v1/dt/targets — add a handle
Resolves the handle against Twitter, stores its numeric ID, and starts monitoring. Idempotent per handle.
Request: {"handle": "elonmusk"}
201 Created:
{"ok":true,"data":{"handle":"elonmusk","twitter_user_id":"44196397"}}Errors: 400 "handle is required" · 403 "Handle limit reached (N/M)" · 409 "@elonmusk is already tracked" · 404 "@elonmusk not found on Twitter" · 502 "Failed to resolve @elonmusk" · 503 upstream/scrape temporarily unavailable.
GET /v1/dt/targets — list handles
Returns your monitored handles and your plan's handle ceiling.
{
"ok": true,
"data": {
"targets": [
{"id": 42, "screen_name": "elonmusk", "display_name": "Elon Musk", "twitter_user_id": "44196397", "is_active": true, "created_at": "2026-07-01T12:00:00Z"}
],
"count": 1,
"max_handles": 500
}
}DELETE /v1/dt/targets/{handle} — remove a handle
{"ok":true,"data":{"removed":"elonmusk"}}Returns 404 "@elonmusk not found" if the handle is not in your set.
GET /v1/dt/status — subscription status
Current handle usage, active state, days remaining, and enabled modules.
{
"ok": true,
"data": {
"targets": 137,
"max_handles": 500,
"is_active": true,
"days_left": 24,
"modules": ["realtime", "follows", "profile_watch"]
}
}GET /v1/dt/profile/{handle} — latest profile snapshot
Most recent stored profile for a monitored handle. Returns 404 "No profile data for @handle yet" until the first profile sync completes.
{
"ok": true,
"data": {
"twitter_id": "44196397",
"screen_name": "elonmusk",
"display_name": "Elon Musk",
"bio": "…",
"location": "…",
"website": "…",
"followers": 190000000,
"following": 800,
"tweet_count": 42000,
"likes_count": 30000,
"listed_count": 150000,
"media_count": 5000,
"is_blue_verified": true,
"verified_type": null,
"avatar_url": "https://pbs.twimg.com/profile_images/…",
"banner_url": "https://pbs.twimg.com/profile_banners/…",
"account_created_at": "2009-06-02T20:12:29Z",
"scraped_at": "2026-07-04T09:15:00Z"
}
}GET /v1/dt/profile/{handle}/history — profile change history
Time series of follower / following / tweet / like / listed counts, newest first. Query params: limit (default 50, max 200), offset (default 0).
{
"ok": true,
"data": {
"history": [
{"followers": 190000000, "following": 800, "tweet_count": 42000, "likes_count": 30000, "listed_count": 150000, "scraped_at": "2026-07-04T09:15:00Z"}
],
"count": 1
}
}GET /v1/dt/tweets/{handle} — recent tweets
Capped at the last 20 tweets captured for the handle (no pagination, no since). Note: engagement metrics (likes, retweets, replies, quotes, views, bookmarks) are returned as 0 and full media metadata (media_types, video_urls) is not populated on this endpoint. For complete tweet objects with media and enrichment, use the realtime WebSocket.
{
"ok": true,
"data": {
"tweets": [
{
"tweet_id": "1234567890123456789",
"full_text": "Hello world",
"created_at": "2026-07-04T09:14:00Z",
"likes": 0, "retweets": 0, "replies": 0, "quotes": 0, "views": 0, "bookmarks": 0,
"is_retweet": false, "is_reply": false, "is_quote": false,
"media_urls": ["https://pbs.twimg.com/media/…"],
"mentions": ["vitalikbuterin"],
"hashtags": [],
"urls": [],
"cashtags": []
}
],
"count": 1
}
}GET /v1/dt/following/{handle} & /v1/dt/followers/{handle}
The accounts a handle follows, or its followers. Query params: limit (default 100, max 500), offset (default 0). The response key is following or followers respectively; total is the full graph size.
GET /v1/dt/following/elonmusk
{
"ok": true,
"data": {
"following": [
{"target_id": "44196397", "target_screen_name": "vitalikbuterin", "is_current": true, "first_seen_at": "2026-06-01T00:00:00Z", "last_seen_at": "2026-07-04T00:00:00Z"}
],
"count": 1,
"total": 800
}
}GET /v1/dt/communities/{handle} — communities
{
"ok": true,
"data": {
"communities": [
{"community_id": "1493446837214187523", "community_name": "Build in Public", "member_count": 120000, "creator_screen_name": "someuser", "is_current": true, "first_seen_at": "2026-06-01T00:00:00Z", "last_seen_at": "2026-07-04T00:00:00Z"}
],
"count": 1
}
}GET /v1/dt/social/diff/{handle} — follow / unfollow diff
This is how you detect unfollows. There is no real-time unfollow event — poll this endpoint. It returns follows added and removed over a trailing 7-day window (up to 100 of each, newest first).
{
"ok": true,
"data": {
"added": [
{"target_id": "44196397", "target_screen_name": "vitalikbuterin", "relation": "following", "change": "added", "changed_at": "2026-07-03T10:00:00Z"}
],
"removed": [
{"target_id": "888", "target_screen_name": "someone", "relation": "following", "change": "removed", "changed_at": "2026-07-02T18:00:00Z"}
],
"added_count": 1,
"removed_count": 1
}
}GET /v1/dt/webhook & PUT /v1/dt/webhook
GET returns your configured callback URL and whether a signing secret is set (the secret itself is never returned by GET). PUT sets the URL (HTTPS only), rotates the signing secret, and returns it once.
GET /v1/dt/webhook
{"ok":true,"data":{"url":"https://your-server.com/webhook","has_secret":true}}
PUT /v1/dt/webhook Request: {"url":"https://your-server.com/webhook"}
{"ok":true,"data":{"url":"https://your-server.com/webhook","secret":"3f9a1c…","note":"Store this secret securely."}}Delivery channel: B2B events are streamed live over the Realtime WebSocket — that is the primary, always-on B2B delivery path. These endpoints store an optional signed-webhook URL for accounts with webhook push enabled.
When a signed delivery is sent, it carries an X-Signature header: a lowercase HMAC-SHA256 hex digest of the raw request body, keyed with the secret returned by PUT. Verify it exactly like the consumer webhook (identical scheme) before trusting the payload:
import hmac, hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature) # signature = X-Signature headerREST Error Codes
Failures return {"ok":false,"error":"…"} with the HTTP status below.
| Status | Meaning | Example error |
|---|---|---|
400 | Bad request — missing/invalid field | "handle is required" |
401 | Auth failed — missing / malformed / invalid dt_ key | "Invalid or inactive API key" |
403 | Handle ceiling reached, or handle not in your target list | "Handle limit reached (500/500)" · "@handle is not in your target list" |
404 | Handle not found on Twitter, or no data yet | "@handle not found on Twitter" |
409 | Handle already in your monitored set | "@handle is already tracked" |
502 | Upstream resolve failed | "Failed to resolve @handle" |
503 | Service temporarily unavailable | "Service temporarily unavailable" |
Limits: REST requests are not per-second rate-limited, but the enforced limits are your plan's handle ceiling (max_handles → 403), a 64 KB request-body cap, and 5 concurrent WebSocket connections per key. High-volume consumers should use the WebSocket rather than polling REST.
Realtime WebSocket
wss://api.xanguard.tech/v1/dt/realtime/wsOpcode-based protocol (HELLO → LOGIN → READY → EVENT stream, TweetCatcher-style). Connect, send the LOGIN opcode with your dt_ API key, and receive real-time events for all monitored handles. See B2B Realtime WebSocket below for the full opcode table, handshake flow, and every event payload.
B2B Realtime WebSocket
High-volume real-time feed with TweetCatcher-compatible opcode protocol. Delivers tweets, follow detection, profile changes, and new follower alerts via a single WebSocket connection. Managed via @B2B_Xanguard_bot.
Connection
wss://api.xanguard.tech/v1/dt/realtime/wsNo query parameter needed — authentication happens via the LOGIN opcode after connecting. Maximum 5 concurrent WebSocket connections per API key.
Opcodes
| Opcode | Name | Direction | Description |
|---|---|---|---|
10 | HELLO | Server → Client | Sent on connect. Includes heartbeat_interval (ms). |
2 | LOGIN | Client → Server | Send your dt_ API key to authenticate. Must be sent within 15 seconds. |
4 | READY | Server → Client | Auth successful. Includes client_id, modules, handles count. |
0 | EVENT | Server → Client | Realtime event data. |
1 | HEARTBEAT | Client → Server | Keep-alive. Send every heartbeat_interval ms. |
11 | HEARTBEAT_ACK | Server → Client | Response to heartbeat. |
3 | DISCONNECT | Server → Client | Connection terminated with reason. |
Handshake Flow
1. Connect → Receive HELLO:
{"op": 10, "d": {"heartbeat_interval": 30000}}2. Send LOGIN with your API key:
{"op": 2, "d": "dt_your_api_key_here"}3. Receive READY on success:
{"op": 4, "d": {"client_id": 1, "modules": ["realtime", "follows", "profile_watch", "followers"], "handles": 150, "max_handles": 1000}}4. Send a HEARTBEAT ({"op": 1}) every heartbeat_interval ms (30s). The server replies with HEARTBEAT_ACK (op 11). If it receives no heartbeat for 90 seconds (3 missed intervals) it closes the connection — reconnect and re-login.
Modules
Modules are configured per client. You only receive events for enabled modules.
| Module | Events | Description |
|---|---|---|
realtime | twitter.post.new, twitter.post.update, twitter.tweet.deleted | Tweets, replies, quotes, retweets in real-time. Initial delivery via twitter.post.new, enriched re-delivery via twitter.post.update. + deleted-tweet alerts. |
follows | twitter.following.new, twitter.following.removed | When a tracked account follows or unfollows someone (follows ~1-3s, unfollows ~3-6s typical) |
profile_watch | twitter.profile.update | Bio, name, avatar, pinned tweet changes (~500ms detection) |
followers | twitter.follower.new | New followers of tracked accounts (~30min digest) |
Delivery semantics: the stream is real-time only — events for tweets older than 30 seconds are dropped (no backfill on connect). Deleted-tweet (twitter.tweet.deleted) and new-follower (twitter.follower.new) events additionally require a per-account opt-in flag; enabling the module alone does not deliver them — ask us to enable deletes / followers on your account.
Event: twitter.post.new
First delivery of a detected tweet — the fastest event, and it carries the full payload: text, media, author, mentions, and ocr_text when OCR is enabled. The only field that can be incomplete is reply/quote context — a tweet caught by a fast push source can arrive with its in_reply_to reference or quoted_tweet body missing, in which case a twitter.post.update follows with those filled in. Store on event_id and merge the update if it arrives.
{
"op": 0,
"d": {
"event": "twitter.post.new",
"event_id": "evt_1234567890123456789",
"task_info": {"handle": "elonmusk"},
"data": {
"id": "1234567890123456789",
"created_at": 1712000000000,
"type": "post",
"text": "Hello world",
"media": [{"type": "photo", "url": "https://pbs.twimg.com/media/..."}],
"mentions": [{"screen_name": "vitalikbuterin"}],
"author": {
"id": "44196397",
"handle": "elonmusk",
"name": "Elon Musk",
"avatar": "https://pbs.twimg.com/profile_images/...",
"description": "CEO of Tesla, SpaceX, etc.",
"verification": {"is_verified": true, "type": "blue"},
"affiliation": null,
"stats": {"followers": 190000000, "following": 800}
},
"in_reply_to": null,
"quoted_tweet": null,
"possibly_sensitive": false,
"ocr_text": "GIGACHAD\nCA: 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"extracted_cas": ["7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"]
}
}
}Tweet types in data.type: "post", "reply", "quote", "repost"
Verification badges: author.verification.type is "blue" (individual), "business" (gold/org), "government" (grey/gov), or null (not verified) — don't treat is_verified alone as a blue check, it is true for all badge types. Affiliated accounts also carry author.affiliation — {"label": "...", "icon_url": "..."} with the small organization/government logo shown next to the handle; null otherwise. Badge data comes from the profile cache and refreshes on the account's poll cycle. Embedded tweets (quoted_tweet, also the parent on replies) include the quoted author's avatar alongside handle/name.
OCR & contract extraction (opt-in): For accounts with OCR enabled, tweets that contain images carry two extra fields inside data: ocr_text — the text read out of the tweet's image(s), or null if none — and extracted_cas — an array of contract addresses (Solana mints, pump.fun links, and EVM 0x addresses) parsed from that image text. For quote tweets, the quoted tweet's images are included (that's usually where the CA image lives); reposts are OCR'd on the original tweet's media. This catches contract addresses posted as images to dodge text scanners, so you see the CA the moment it drops. Both fields are omitted entirely for accounts without OCR.
Event: twitter.post.update
A context correction for a previously sent tweet — emitted only when the fast source detected a reply or quote without its full context, or (for OCR-enabled accounts) when a push-sourced event shipped without media that later hydration recovered. It re-delivers the same payload with type, in_reply_to, quoted_tweet corrected and, in the media-recovery case, media / ocr_text / extracted_cas filled in; every other field already arrived complete in twitter.post.new. Shares the same data.id and the same event_id (evt_<tweet_id>) as the original — dedupe on event_id and replace the stored data for this tweet.
{
"op": 0,
"d": {
"event": "twitter.post.update",
"event_id": "evt_1234567890123456789",
"task_info": {"handle": "elonmusk"},
"data": {
"id": "1234567890123456789",
"created_at": 1712000000000,
"type": "quote",
"text": "This is huge 👀",
"media": [],
"mentions": [],
"author": {
"id": "44196397",
"handle": "elonmusk",
"name": "Elon Musk",
"avatar": "https://pbs.twimg.com/profile_images/...",
"description": "CEO of Tesla, SpaceX, etc.",
"verification": {"is_verified": true, "type": "blue"},
"affiliation": null,
"stats": {"followers": 190000000, "following": 800}
},
"in_reply_to": null,
"quoted_tweet": {
"id": "9876543210987654321",
"text": "Original tweet text here",
"author": {"handle": "vitalikbuterin", "name": "Vitalik Buterin", "avatar": "https://pbs.twimg.com/profile_images/..."}
},
"possibly_sensitive": false
}
}
}Event: twitter.tweet.deleted
{
"op": 0,
"d": {
"event": "twitter.tweet.deleted",
"event_id": "evt_del_elonmusk_1712000000",
"task_info": {"handle": "elonmusk"},
"data": {"tweet_id": "1234567890123456789"}
}
}data.tweet_id may be null if the specific tweet id could not be determined.
Event: twitter.following.new
{
"op": 0,
"d": {
"event": "twitter.following.new",
"event_id": "evt_f_elonmusk_1712000000",
"task_info": {"handle": "elonmusk"},
"data": {
"id": "44196397",
"handle": "vitalikbuterin",
"name": "Vitalik Buterin",
"bio": "Ethereum",
"followers": 5200000,
"following": 350,
"protected": false
}
}
}Event: twitter.following.removed
Fires when a tracked account unfollows someone it previously followed. Same data shape as twitter.following.new — it identifies the account that was unfollowed. data.name/data.handle may be null if we no longer have that profile cached.
{
"op": 0,
"d": {
"event": "twitter.following.removed",
"event_id": "evt_fr_elonmusk_1712000000",
"task_info": {"handle": "elonmusk"},
"data": {
"id": "44196397",
"handle": "vitalikbuterin",
"name": "Vitalik Buterin",
"bio": "Ethereum",
"followers": 5200000,
"following": 350,
"protected": false
}
}
}Testing follow / unfollow: add a Twitter account you control via POST /v1/dt/targets, connect the WebSocket, then from that account follow (or unfollow) any other user on Twitter. Within ~30–60 seconds you'll get a twitter.following.new (or twitter.following.removed) event on the stream. Detection is poll-based — Twitter exposes no real-time push for follow-graph changes — so it's seconds, not instant. Requires the follows module enabled on your account.
Event: twitter.profile.update
{
"op": 0,
"d": {
"event": "twitter.profile.update",
"event_id": "evt_p_elonmusk_1712000000",
"task_info": {"handle": "elonmusk"},
"data": {
"field": "description",
"prev": "Old bio text",
"updated": "New bio text"
}
}
}Fields: "description", "name", "avatar", "pinned_post"
Event: twitter.follower.new
{
"op": 0,
"d": {
"event": "twitter.follower.new",
"event_id": "evt_fl_elonmusk_1712000000",
"task_info": {"handle": "elonmusk"},
"data": {
"id": "555555555",
"handle": "newfollower",
"name": "New Follower"
}
}
}Example: JavaScript Client
const ws = new WebSocket('wss://api.xanguard.tech/v1/dt/realtime/ws');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.op) {
case 10: // HELLO
ws.send(JSON.stringify({op: 2, d: 'dt_YOUR_API_KEY'}));
break;
case 4: // READY
console.log('Connected:', msg.d.modules, msg.d.handles, 'handles');
break;
case 0: // EVENT
console.log('Event:', msg.d.event, msg.d.data);
break;
}
};
// Heartbeat every 30s
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({op: 1}));
}
}, 30000);Example: Python Client
import asyncio, websockets, json
async def connect():
async with websockets.connect('wss://api.xanguard.tech/v1/dt/realtime/ws') as ws:
hello = json.loads(await ws.recv()) # HELLO
await ws.send(json.dumps({"op": 2, "d": "dt_YOUR_API_KEY"}))
ready = json.loads(await ws.recv()) # READY
print(f"Connected: {ready['d']['modules']}, {ready['d']['handles']} handles")
while True:
msg = json.loads(await ws.recv())
if msg["op"] == 0: # EVENT
print(f"{msg['d']['event']}: {msg['d']['data']}")
asyncio.run(connect())Pricing
Priced by module tier and handle count — see the full table under Xanguard B2B → Pricing.
CA Search
CA Search is a B2B Extra Feature: full tweet search by contract address, ticker, cashtag, or any keyword — the same results you would get on the X search page, returned as structured JSON with complete tweet and author metadata. Built for trading apps that need to show who called a token and what they said, without sending users to x.com.
It answers the questions degens ask about any CA: which accounts posted it, how big they are, what reach the token has, and the full context of every quote, retweet, and reply.
Endpoint
POST https://api.xanguard.tech/v1/searchUses your B2B (dt_) API key — issued when you activate CA Search in @B2B_Xanguard_bot, with or without a base B2B subscription (standalone works). Both auth header styles are accepted:
Authorization: Bearer dt_your_api_key_here
# or, twitterapi.io-compatible:
X-API-Key: dt_your_api_key_hereRequest Body
| Field | Type | Description |
|---|---|---|
query | string | Required, 1–200 chars. Contract address, $TICKER, cashtag, or any keywords. |
cursor | string | Optional. Pass the previous response's next_cursor to continue a truncated result set. |
since | string | Optional. Window start — RFC3339 (2026-07-20T00:00:00Z), YYYY-MM-DD (midnight UTC), or unix epoch (s or ms). Defaults to 24 hours ago. |
until | string | Optional. Window end (exclusive) — same formats as since. Use with since to query a historical window, e.g. {"query": "...", "since": "2026-07-20", "until": "2026-07-25"}. |
curl -X POST https://api.xanguard.tech/v1/search \
-H "Authorization: Bearer dt_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"query": "0x7a848a5a8169aa6a2f603d056a749f924f504444"}'Historical window example:
curl -X POST https://api.xanguard.tech/v1/search \
-H "Authorization: Bearer dt_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"query": "0x7a848a5a8169aa6a2f603d056a749f924f504444", "since": "2026-07-20", "until": "2026-07-25"}'Response
Standard envelope. Each call walks the search timeline backwards through the window — the last 24 hours by default (data.window_hours), or a custom range when since/until are supplied (echoed back as data.since / data.until) — and returns
up to 200 tweets per call in data.tweets, each with full engagement metrics and a complete author object.
Very hot queries (or long windows) that exceed 200 tweets come back with has_next_page: true — pass next_cursor as cursor to continue. Each call (including cursor continuations) counts once against your daily search allowance.
data.summary aggregates the result set: how many unique authors posted, their combined follower reach, and the top 5 callers by followers.
{
"ok": true,
"data": {
"tweets": [
{
"type": "tweet",
"id": "1947000000000000000",
"url": "https://x.com/hongxiao_sol/status/1947000000000000000",
"text": "$EXAMPLE just launched, CA: 0x7a84…4444",
"createdAt": "Sun Jul 20 10:15:00 +0000 2026",
"retweetCount": 3,
"replyCount": 1,
"likeCount": 42,
"quoteCount": 0,
"viewCount": 5100,
"bookmarkCount": 2,
"lang": "en",
"isReply": false,
"inReplyToId": "",
"inReplyToUsername": "",
"conversationId": "1947000000000000000",
"author": {
"userName": "hongxiao_sol",
"name": "Hong",
"id": "1500000000000000000",
"followers": 11145,
"following": 320,
"isBlueVerified": true,
"profilePicture": "https://pbs.twimg.com/profile_images/…",
"description": "sol maxi",
"location": "",
"createdAt": "Mon Mar 15 09:00:00 +0000 2021",
"statusesCount": 8900,
"mediaCount": 1200,
"favouritesCount": 4500
},
"entities": {"hashtags": [], "urls": [], "user_mentions": []},
"quoted_tweet": null,
"retweeted_tweet": null
}
],
"summary": {
"total_tweets": 20,
"unique_authors": 17,
"total_reach": 208122,
"top_callers": ["@whalecaller", "@hongxiao_sol"]
},
"window_hours": 24,
"has_next_page": false,
"next_cursor": null
}
}Quote, Retweet & Reply Context
Every tweet keeps its full context, so you can render the original content alongside reposts and replies:
| Field | Present when | Contents |
|---|---|---|
quoted_tweet | The tweet quotes another; for replies it carries the parent tweet | Nested tweet object: id, url, text, author, metrics |
retweeted_tweet | The tweet is a repost | Nested tweet object of the original |
original | The tweet is a reply | The parent tweet: id, text, author username |
Plans & Limits
CA Search is a monthly plan — standalone or on top of your B2B subscription (activate in @B2B_Xanguard_bot → Extra Features):
| Plan | Daily searches | Price |
|---|---|---|
| CA Search 1K | 1,000/day (~30k/mo) | $100/mo |
| CA Search 2K | 2,000/day (~60k/mo) | $180/mo |
| CA Search 5K | 5,000/day (~150k/mo) | $250/mo |
| Limit | Value |
|---|---|
| Rate limit | 10 requests/sec and 20 requests/min per API key |
| Results per call | Up to 200 tweets per call (default window: last 24h; custom via since/until) — continue with cursor for hotter queries or longer windows |
Every response (including 429s) carries your quota state as headers — check them instead of hard-coding plan values:
| Header | Meaning |
|---|---|
X-RateLimit-Daily-Limit | Your plan's daily search allowance (e.g. 1000) |
X-RateLimit-Daily-Remaining | Searches left today (UTC day) after this request |
X-RateLimit-Minute-Limit | Burst ceiling per rolling minute (20) |
X-RateLimit-Minute-Remaining | Burst allowance left in the current minute window |
| Status | Meaning | Example error |
|---|---|---|
400 | Missing or oversized query | "Query must be 1-200 characters" |
401 | Missing / invalid dt_ key | "Invalid or inactive API key" |
403 | CA Search add-on not enabled on this key | "CA Search is not enabled for this key" |
429 | Rate limit or daily allowance exhausted | "Daily search limit reached (1000/1000)" |
500 | Upstream search failure — retry | "Search failed" |
Add-on feature. CA Search is enabled per B2B subscription. Buy it under Extra Features → CA Search in @B2B_Xanguard_bot — SOL payment, automatic activation on confirmation.
CW API & Webhooks
CW has its own REST API and webhook delivery system, separate from the main Xanguard API.
Authentication
All CW API requests require your CW API key (generated via /apikey in the bot). Pass it as a header:
Authorization: Bearer cw_your_api_key_here
Base URL: https://api.xanguard.tech/v1/cw
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /v1/cw/targets | List all monitored accounts |
| POST | /v1/cw/targets | Add an account to monitor. Body: {"handle": "elonmusk"} |
| DELETE | /v1/cw/targets/{handle} | Remove a target |
| GET | /v1/cw/webhook | Get configured webhook URL |
| PUT | /v1/cw/webhook | Set webhook URL |
| GET | /v1/cw/settings | Get current filter settings |
| PATCH | /v1/cw/settings | Update filter settings |
| GET | /v1/cw/status | Subscription status, handles tracked, expiry |
| WS | /v1/cw/ws | WebSocket stream of CW events |
Webhook Format
Configure your webhook URL via /settings in the bot or PUT /v1/cw/webhook. CW sends a signed POST request per event. Every community-change delivery uses the constant event name community_change — the specific type is inside data.event_type:
{
"event": "community_change",
"timestamp": 1784646000000,
"data": {
"event_type": "community_joined",
"screen_name": "elonmusk",
"twitter_user_id": "44196397",
"community_id": "1493446837214187523",
"community_name": "Crypto Builders",
"description": "…",
"member_count": 15420,
"creator_screen_name": "someuser",
"detected_at": 1784645998000,
"detection_latency_ms": 1400
}
}
data.event_type is one of: community_created, community_joined, community_renamed (adds old_name), community_description_changed (adds old_description), account_followed, new_follower. Timestamps are epoch milliseconds.
New-follower events arrive as a batch digest with their own envelope:
{
"event": "new_followers",
"timestamp": 1784646000000,
"data": {
"screen_name": "elonmusk",
"twitter_user_id": "44196397",
"followers": [
{"user_id": "123", "screen_name": "newfan", "display_name": "New Fan", "followers_count": 320, "following_count": 150, "account_age_days": 400}
],
"detected_at": 1784645998000
}
}
Follow events (account_followed) use their own envelope:
{
"event": "follow_change",
"timestamp": 1784646000000,
"data": {
"screen_name": "elonmusk",
"twitter_user_id": "44196397",
"followed_user_id": "783214",
"followed_screen_name": "someuser",
"followed_display_name": "Some User",
"followed_bio": "…",
"followed_followers_count": 12000,
"detected_at": 1784645998000
}
}
Deliveries carry an X-Signature HMAC-SHA256 header (same verification scheme as the main API) and are retried with backoff on non-2xx responses.
CT API
All CT API requests require a Bearer token with ct_ prefix, generated via /apikey in the bot.
Authorization: Bearer ct_your_api_key_hereEndpoints
| Method | Path | Description |
|---|---|---|
| GET | /v1/ct/targets | List tracked targets |
| POST | /v1/ct/targets | Add target. Body: {"handle": "username"} |
| DELETE | /v1/ct/targets/{handle} | Remove target |
| GET | /v1/ct/convergence | Current convergence detections |
| GET | /v1/ct/convergence/history | Historical convergence events |
| GET | /v1/ct/settings | Get CT settings (min_convergence, time_window_hours, min_member_count) |
| PATCH | /v1/ct/settings | Update settings |
| GET | /v1/ct/webhook | Get webhook URL |
| PUT | /v1/ct/webhook | Set webhook URL. Body: {"url": "https://..."} |
| GET | /v1/ct/status | Subscription status |
WebSocket
wss://api.xanguard.tech/v1/ct/ws?api_key=ct_your_keyReceives real-time JSON events when convergence is detected.
ECA API
Programmatic access to ECA (Early CA Alerts) — the pump.fun launch watchlist. For bot commands & pricing, see the ECA Telegram guide.
Auth: Bearer token with eca_ prefix.
Authorization: Bearer eca_your_api_key_here| Method | Path | Description |
|---|---|---|
| GET | /v1/eca/watchlist | List active watchlist entries |
| POST | /v1/eca/watchlist | Add entry. Body: {"ticker": "DOGE", "token_name": "...", "contract_address": "...", "creator_address": "..."} |
| DELETE | /v1/eca/watchlist/{id} | Remove entry |
| GET | /v1/eca/matches | Recent token matches (last 24h) |
| GET | /v1/eca/webhook | Get webhook URL |
| PUT | /v1/eca/webhook | Set webhook URL |
| GET | /v1/eca/status | Active entries, total matches |
WebSocket
wss://api.xanguard.tech/v1/eca/ws?api_key=eca_your_keyReceives real-time JSON events when a token launch matches your watchlist criteria.
Engagement Tracker API
Programmatic access to Engagement Tracker — per-tweet engagement monitoring. For bot commands & pricing, see the Engagement Tracker Telegram guide.
Auth: Bearer token with et_ prefix.
Authorization: Bearer et_your_api_key_here| Method | Path | Description |
|---|---|---|
| GET | /v1/et/targets | List watched tweets |
| POST | /v1/et/targets | Add tweets. Body: {"tweet_ids": ["123", "456"]} |
| DELETE | /v1/et/targets/{tweet_id} | Remove watched tweet |
| GET | /v1/et/engagement/{tweet_id} | Current engagement counts |
| GET | /v1/et/webhook | Get webhook URL |
| PUT | /v1/et/webhook | Set webhook URL |
| GET | /v1/et/status | Subscription status |
Engagement Response
{
"ok": true,
"data": {
"tweet_id": "1234567890",
"favorite_count": 42,
"retweet_count": 10,
"reply_count": 5,
"quote_count": 2,
"bookmark_count": 8,
"last_updated": "2026-03-22T11:30:00Z"
}
}
WebSocket
wss://api.xanguard.tech/v1/et/ws?api_key=et_your_keyReceives real-time JSON events when engagement counts change for any watched tweet.
Trending Alerts API
Programmatic access to Trending Alerts — the real-time trending feed. For bot commands & pricing, see the Trending Alerts Telegram guide.
Auth: Bearer token with trend_ prefix.
Authorization: Bearer trend_your_api_key_here| Method | Path | Description |
|---|---|---|
| GET | /v1/trending/categories | List all 24 categories with subscription status |
| GET | /v1/trending/subscriptions | Your subscribed categories |
| PUT | /v1/trending/subscriptions | Update subscriptions. Body: {"categories": ["crypto", "tech"]} |
| GET | /v1/trending/webhook | Get webhook URL |
| PUT | /v1/trending/webhook | Set webhook URL |
| GET | /v1/trending/status | Subscription status |
WebSocket
wss://api.xanguard.tech/v1/trending/ws?api_key=trend_your_keyReceives real-time JSON events when new trending tweets are detected in your subscribed categories.
PumpFun Livestream API
Programmatic access to PumpFun Livestream — livestream start/stop detection for watched wallets. For bot commands & pricing, see the PumpFun Livestream Telegram guide.
Auth: Bearer token with pf_ prefix.
Authorization: Bearer pf_your_api_key_here| Method | Path | Description |
|---|---|---|
| GET | /v1/pf/targets | List watched wallets |
| POST | /v1/pf/targets | Add wallet. Body: {"wallet_address": "DYw8j...", "label": "Dev1"} |
| DELETE | /v1/pf/targets/{wallet} | Remove wallet |
| GET | /v1/pf/events | Recent livestream events (max 50) |
| GET | /v1/pf/webhook | Get webhook URL |
| PUT | /v1/pf/webhook | Set webhook URL |
| GET | /v1/pf/status | Subscription status |
Event Response
{
"ok": true,
"data": [
{
"wallet_address": "DYw8j...",
"mint": "9PR3c...",
"token_name": "BONK",
"token_symbol": "BONK",
"event_type": "livestream_started",
"detected_at": "2026-03-22T10:15:00Z",
"delivery_latency_ms": 450
}
]
}
WebSocket
wss://api.xanguard.tech/v1/pf/ws?api_key=pf_your_keyReceives real-time JSON events when watched wallets start or stop livestreaming on pump.fun.
Search Alerts API
Programmatic access to Search Alerts — keyword search alerts. For bot commands & pricing, see the Search Alerts Telegram guide.
Auth: Bearer token with sa_ prefix, generated via the API Key button in the Search Alerts management screen.
Authorization: Bearer sa_your_api_key_here| Method | Path | Description |
|---|---|---|
| GET | /v1/sa/queries | List search queries |
| POST | /v1/sa/queries | Add query. Body: {"query_text": "solana airdrop"} |
| DELETE | /v1/sa/queries/{id} | Remove query |
| GET | /v1/sa/webhook | Get webhook URL |
| PUT | /v1/sa/webhook | Set webhook URL |
| GET | /v1/sa/status | Subscription status, query count, max queries |
Match Event
{
"type": "search_alert",
"data": {
"query_id": 1,
"query_text": "solana airdrop",
"tweet_id": "1234567890",
"full_text": "Massive Solana airdrop incoming...",
"screen_name": "CryptoWhale",
"display_name": "Crypto Whale"
}
}
WebSocket
wss://api.xanguard.tech/v1/sa/ws?api_key=sa_your_keyReceives real-time JSON events when new tweets match your keyword queries.
Changelog
2026-07-21
- CA Search launched:
POST /v1/searchB2B add-on — tweet search by contract address, ticker, or keyword with 24h deep pagination. Plans from $100/mo. See CA Search. - Docs restructured into API docs and Telegram guides.
Support
Need help getting set up or have questions about the API? Reach out through any of these channels.
Telegram Guides
Bot setup, commands, and user guides for every product live on the Telegram guides page.
Direct Contact
For account issues, billing questions, or enterprise inquiries, message @notAdegen on Telegram.
Blog
Read the Xanguard Blog for guides, analysis, and product updates.
Main Site
Visit xanguard.tech for an overview of the platform, feature highlights, and FAQ.