Get public X profile data with Python for lead enrichment
Look up follower counts, bio and verification for a public X profile with one request and no developer account, plus exactly what the endpoint does not cover. Tested August 2026.

Before you email a creator or add a lead to a list, you want the basics: how many followers do they actually have, is the account verified, what does the bio say, when was it created. That is a public-profile lookup, not a research project, and /v1/x answers exactly that with one request.
X’s own developer platform can answer the same question, but only after you register an app, get approved, and pick a paid tier, a real setup cost if all you need is a follower count on a handful of leads a week. This endpoint skips that: it is a normal REST call against public profile data, billed per lookup instead of per subscription.
One parameter: profileId
The only parameter is profileId, camelCase, and it is the username without the @. Pass elonmusk, not @elonmusk and not a profile URL. If your source list has usernames copied straight off X or out of a profile link, strip the @ and any surrounding URL before you build the request, since profileId is documented as the bare handle.
import requests
API_KEY = "faf_live_..." # your FastAF key
resp = requests.get(
"https://api.fastaf.co/v1/x",
params={"profileId": "elonmusk"},
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=60,
)
resp.raise_for_status()
profile = resp.json()["profile"]
stats = profile["stats"]
print(f'{profile["name"]} ({profile["username"]})')
print(f'verified: {profile["is_blue_verified"]}')
print(f'followers: {stats["followers"]:,} following: {stats["following"]:,} tweets: {stats["tweets"]:,}')
print(f'bio: {profile["description"]}')
print(f'created: {profile["created_at"]}')
That is 5 credits. Everything nests under a profile object first, and the counters nest again one level deeper under profile["stats"], which is the part people guess wrong before they check: followers is not top-level.
What you actually get
Running the call above against a real, well-known account returned a profile object with: name, username (this one comes back with the @ included, even though the request parameter does not take it), user_id, description (the bio), location, website, created_at, is_blue_verified, verified_type, protected, possibly_sensitive, and image fields (profile_image, profile_banner). Nested under stats: followers, following, tweets, and creator_subscriptions. For that particular account the numbers were a followers count north of 241 million, following at 1,396, and tweets at 107,673, all plain integers, no formatting to strip. That is enough to build a real vetting rule, for example rejecting anything under a follower floor, or an account-age check computed from created_at.
location came back null on this account, which is a reminder that profile fields are only as complete as what the person filled in on X: treat every field except the identity basics (name, username, user_id) as optional when you write the code that consumes this.
What it does not do
Be clear with yourself about scope before you build a pipeline on this: /v1/x returns one profile, once, per call. It does not return that account’s posts, it does not return a list of their followers or who they follow, and it is not a search: you need the exact username already, from a lead form, a CSV, a mention, wherever your list comes from. If your workflow needs “find accounts talking about X” rather than “tell me about this specific account,” this endpoint is the wrong tool for that step.
It is also a snapshot, not a subscription: nothing pushes you an update when a follower count crosses a threshold or a bio changes. If you need that, call it again on your own schedule and diff the stats you get back against what you stored last time, the same way you would track any other number that changes over time.
Vetting and enrichment, concretely
The common pattern is a batch job: a list of usernames in, a scored or filtered list out. Keep the filter itself simple and specific to what you actually need, a follower floor, a verified check, an account-age cutoff, rather than trying to compute a single “influencer score” from fields that were never designed to combine into one.
def enrich(usernames, min_followers=10_000):
qualified = []
for handle in usernames:
resp = requests.get(
"https://api.fastaf.co/v1/x",
params={"profileId": handle},
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=60,
)
resp.raise_for_status()
p = resp.json()["profile"]
if p["stats"]["followers"] >= min_followers:
qualified.append({
"username": p["username"],
"followers": p["stats"]["followers"],
"verified": p["is_blue_verified"],
"bio": p["description"],
})
return qualified
Wrap each call in a try/except in production: a deactivated or suspended account is a real possibility in any list you did not just generate yourself, and you want that to skip a row, not stop the batch.
What this costs
| Volume | Credits | Pack that covers it | Cost |
|---|---|---|---|
| 500 leads, one-off vetting pass | 2,500 | Growth, $29 | ~$0.97 of the pack |
| 5,000 profiles enriched in 30 days | 25,000 | Growth, $29 | ~$9.67 of the pack |
| 50,000 profiles enriched in 30 days | 250,000 | Scale, $99 | ~$82.50 of the pack |
Failed requests are never billed: credits are reserved when a request starts and returned if it does not come back with a result. The free tier is 500 credits with no card, which covers 100 profile lookups, plenty to check field coverage on your own list before you commit to a schedule.