Tracked accounts
Tracked accounts determine what arrives live and which stored content, profile, follow, and affiliate events History API can return. Manage them in the dashboard or from your own backend.
Add and remove accounts
The accounts field accepts one handle or an array of handles. The leading @ is optional, and handle matching is case-insensitive. A standard API key updates the standard tracked-account list; an active Ultra API key updates the Ultra selection and enforces its paid account limit.
const response = await fetch("https://api.tweetstream.io/api/add-account", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TWEETSTREAM_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
accounts: ["marketdesk", "realDonaldTrump"],
}),
});
console.log(await response.json());const response = await fetch("https://api.tweetstream.io/api/remove-account", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.TWEETSTREAM_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
accounts: "marketdesk",
}),
});
console.log(await response.json());{
"action": "follow",
"requestId": "8b4f9c9c-9e7b-4a0c-9c7d-2d4d6f0a9a25",
"error": null,
"results": [
{
"input": "marketdesk",
"state": "added"
},
{
"input": "realDonaldTrump",
"state": "added"
}
],
"summary": {
"failed": 0,
"succeeded": 2,
"total": 2
}
}Read current usage
`/api/me` accepts either the standard or Ultra API key. It returns base-plan usage and any additive Ultra Speed details. The response is private and is not cached.
| Field | Type | Notes |
|---|---|---|
| credentialScope | standard or ultra_speed | Scope of the bearer key used |
| plan | BASIC, ELITE, or ENTERPRISE | Runtime plan enum |
| trackedAccounts | object | Count, limit, and normalized handles |
| websocket | object | Current active connection count and plan limit |
| stripe | object | Subscription status and billing period fields; identifiers should be treated as private |
| ultraSpeed | object or null | Ultra status, billing cycle, limits, scoped WebSocket usage, and cancellation timing |
const response = await fetch("https://api.tweetstream.io/api/me", {
headers: {
Authorization: `Bearer ${process.env.TWEETSTREAM_API_KEY}`,
},
});
console.log(await response.json());{
"credentialScope": "standard",
"plan": "ELITE",
"trackedAccounts": {
"count": 2,
"limit": 250,
"handles": ["marketdesk", "realDonaldTrump"]
},
"websocket": {
"count": 1,
"limit": 10
},
"stripe": {
"subscriptionStatus": "ACTIVE",
"customerId": "[redacted]",
"hasCustomer": true,
"subscriptionId": "[redacted]",
"currentPeriodStart": "2026-06-30T00:00:00.000Z",
"currentPeriodEnd": "2026-07-30T00:00:00.000Z",
"canceledAt": null
},
"ultraSpeed": {
"active": true,
"status": "ACTIVE",
"billingCycle": "MONTHLY",
"paymentRail": "STRIPE_CARD",
"accountLimit": 25,
"websocket": {
"count": 1,
"limit": 5
},
"currentPeriodEnd": "2026-07-30T00:00:00.000Z",
"cancelAtPeriodEnd": false,
"canceledAt": null
}
}Affiliate list changes
Affiliate list changes are off by default for tracked business accounts on active or trialing Pro, Scale, and Ultra plans. Turn them on with `POST /api/affiliate-alerts` and off with `DELETE /api/affiliate-alerts`, or use the dashboard. Send the tracked handle as `account`; the leading @ is optional. Repeating the same request is safe. Success returns `{ account, affiliateAlertsEnabled }`. When you turn alerts on, TweetStream checks that the account still qualifies as a business account. Otherwise, the API returns `400` with `{ error: "This account is not a business account." }`. When TweetStream detects a change, it sends the event through WebSocket, the dashboard feed, and your Discord route. Replay recorded changes with `GET /api/history?type=affiliate`. Keyword filters do not apply. Store relationships by `(organization.id, member.id)` and use `eventId` only to deduplicate exact replays. There is no current-list snapshot or pre-feature backfill.
| Status | When it appears | Action |
|---|---|---|
| 200 | The saved setting matches the request | Read affiliateAlertsEnabled |
| 400 | The body is invalid or the account is not a business account | Fix the request |
| 401 | The bearer key is missing or invalid | Send a valid API key |
| 403 | The subscription or feature access is inactive | Check plan access |
| 404 | The handle is not tracked by this API key | Check the tracked handle |
| 500 | TweetStream could not confirm eligibility | Retry later |
async function setAffiliateAlerts(account: string, enabled: boolean) {
const response = await fetch("https://api.tweetstream.io/api/affiliate-alerts", {
method: enabled ? "POST" : "DELETE",
headers: {
Authorization: `Bearer ${process.env.TWEETSTREAM_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ account }),
});
if (!response.ok) {
throw new Error(await response.text());
}
return await response.json();
}
console.log(await setAffiliateAlerts("marketdesk", true));
console.log(await setAffiliateAlerts("marketdesk", false));Handle result states
| State | When it appears | Recommended handling |
|---|---|---|
| added | Handle was added to the watchlist | Treat as success |
| already_following | Handle is already tracked | Treat as idempotent at the row level |
| removed | Handle was removed | Treat as success |
| not_following | Handle was not tracked | Treat as idempotent at the row level |
| invalid_input, duplicate, not_found, failed | Invalid input, duplicate input, missing account, or operation failure | Show the row-level message and retry only when appropriate |
REST status codes
The add and remove endpoints return one result per handle. The HTTP status describes the batch outcome, while each result row describes what happened to that handle.
| Status | When it appears | Notes |
|---|---|---|
| 200 | No row failed, including idempotent success rows | summary.failed is 0; already_following and not_following are successful outcomes |
| 207 | Some rows succeeded and some rows failed | Read each results row before retrying |
| 400 | The request body is invalid or every row failed for a non-temporary reason | Fix the request or row-level errors before retrying |
| 503 | Every row failed for a temporary reason | Retry the batch with backoff |
Plan limits
- Minimum: 50 monitored accounts and 3 WebSocket connections after trial.
- Trial: 5 monitored accounts and 1 WebSocket connection for 3 days.
- Pro: 250 monitored accounts and 10 WebSocket connections.
- Scale: self-serve higher monitored-account and WebSocket limits from the pricing page.
- History replay is available on Pro and Scale; Ultra includes affiliate replay.