What an X Profile API Snapshot Can Tell You About a Public Account
A public X profile API snapshot can record returned profile fields and a short recent-post list for a known handle. Preserve the requested and returned identities, observation time and missing values. The snapshot cannot establish a full timeline, a follower list or every post in a date range.
I founded Serpent API, so this guide is affiliated. On October 5, 2026, I reviewed its published profile contract and X’s developer platform. The example has no authenticated parsed production result; check access and returned account identity before using a snapshot in a report.
Start from a known public handle
Start with a known handle, not a query. Decide whether the profile name, bio, website and three counts answer the review question. If recent posts matter, keep each returned post ID and URL, but do not infer that the array contains every post in a period. A protected or new account can yield an empty recent_posts array while the profile is still a valid response.
The Serpent profile endpoint accepts a handle or profile URL. Check profile.handle against the requested handle, then store counts.followers, following and posts as nullable values. The base recent_posts rows have id, URL, text snippet and created_at. hydrate=true may add exact text, counts and media to individual posts; branch on those keys per post instead of assuming uniform enrichment.
Separate profile and post fields
X’s official developer platform has its own pay-per-use access and endpoint permissions. Serpent exposes a narrower public profile snapshot. This article has no authenticated parsed production response for its example handle. Confirm account access and returned fields before building against it.
| Field or input | Use | Interpretation check |
|---|---|---|
| handle, name, bio, website | Capture identity and profile context. | No verified badge field is promised on the profile. |
| counts.followers, following, posts | Keep nullable stated counts. | Null is unknown, not zero. |
| recent_posts[].id, url, text, created_at | Record returned recent-post sample. | The array is not a full timeline. |
| hydrated post counts, media | Read only when the keys are present. | Hydration is per post and best-effort. |
Save a public profile snapshot in Python
Set SERPENT_API_KEY and install requests. The example below includes request authentication, a bounded timeout, a parsed success check and explicit missing-data handling. Its syntax was checked; production values and access remain to be validated with an authorized account. Replace the illustrative handle, ID or tag with one you are permitted to review.
import os
from datetime import datetime, timezone
import requests
BASE = "https://apiserpent.com"
KEY = os.environ["SERPENT_API_KEY"]
def fetch(path, params):
response = requests.get(BASE + path, params=params,
headers={"X-API-Key": KEY}, timeout=60)
if response.status_code == 404:
# HTTP status alone cannot separate route access from resource absence.
return {"lookup": "unverified_404", "observed_at":
datetime.now(timezone.utc).isoformat()}
response.raise_for_status()
data = response.json()
if data.get("success") is not True:
raise ValueError("No usable response")
data["observed_at"] = datetime.now(timezone.utc).isoformat()
return data
handle = "example"
data = fetch("/api/x/profile", {"handle": handle, "hydrate": "true"})
if data.get("lookup") == "unverified_404":
print({"handle": handle, "status": "unverified API 404; check route access and request",
"observed_at": data["observed_at"]})
else:
profile = data.get("profile")
if not isinstance(profile, dict) or (profile.get("handle") or "").lower() != handle:
raise ValueError("Profile identity did not match")
counts = profile.get("counts") or {}
posts = profile.get("recent_posts")
if not isinstance(counts, dict) or not isinstance(posts, list):
raise ValueError("Unexpected profile shape")
recent = []
for post in posts:
if not isinstance(post, dict):
continue
recent.append({"id": post.get("id"), "url": post.get("url"),
"text": post.get("text"),
"favorites": post.get("counts", {}).get("favorites")
if isinstance(post.get("counts"), dict) else None,
"hydrated": "counts" in post or "media" in post})
print({"handle": handle, "name": profile.get("name"),
"followers": counts.get("followers"),
"following": counts.get("following"),
"posts_count": counts.get("posts"),
"recent_returned": len(posts), "recent": recent,
"observed_at": data["observed_at"]})
Interpret the printed record carefully. The sample checks each recent post independently for hydration fields. A post without counts is not assigned zero favorites, and an empty recent_posts list is not converted into “this account has never posted.” Save the requested hydrate choice and the returned row-level field presence so later reports can explain why counts are absent.
Budget repeat account checks
The documented X Profile rate is flat across Serpent tiers at $0.10 per 1,000 requests. hydrate=true is 1.5×, or $0.15 per 1,000, where enrichment is delivered. A weekly audit of 100 handles over four weeks is 400 calls: $0.04 base or $0.06 at the hydrated planning rate. The actual ledger can reflect the documented premium adjustment when no recent post was enriched. Do not assume a higher account tier discounts this profile endpoint.
These are dated contract calculations, not a live invoice or a guarantee of result quality. See Serpent pricing for current tier terms, and inspect your account ledger after a small verified run. Do not divide a bill by returned items when the published unit is a request or requested depth.
When official X access fits
| Option | Best use | Access or billing unit | Decision |
|---|---|---|---|
| Official X developer platform | Direct API integration under official access and permissions. | Pay-per-use positioning; verify endpoint-specific current terms in X documentation. | Choose when your requirements fit official access and policy. |
| Serpent X profile base | Public profile and listed recent-post snippets. | $0.10/1K requests at every Serpent tier. | Choose for a narrow profile snapshot after you verify parsed output on your account. |
| Serpent X profile hydrated | Exact post text, counts and media where individual rows fill. | $0.15/1K requests at every tier when the 1.5× premium applies. | Choose only if those extra post fields affect the audit. |
Why a profile snapshot may mislead
A handle can change, an account can become protected, and counts can move between snapshots. The profile response has no verified field; do not infer verification from a badge seen elsewhere. Recent posts do not form a full timeline, and there is no follower list. A 404 does not identify why a handle was not returned. Do not infer account activity from one short or empty recent list.
Separate account identity, profile changes and post coverage
A handle is an input and can change. Store the returned account identifier if the response supplies one, plus the requested and returned handles, profile URL and observation time. Do not merge two snapshots solely because the display name matches. If the returned handle differs from the request, hold the row for identity review before treating it as the same account. Keep profile counts separate from the recent_posts sample: a post count does not tell you which posts were returned.
| Two-run change | Safe finding | Check first |
|---|---|---|
| Bio or website changed on matched identity | Different values in two dated snapshots | Open the profile for current context. |
| Follower counts differ and both are numeric | Two observed counts | Do not assign a cause to the movement. |
| Recent post absent from later short list | Not returned in the later sample | Open its URL; do not declare deletion. |
| Hydrated detail missing on one post | That post's detail is unknown | Do not apply another post's counts to it. |
Choose hydrate=true only if exact recent-post text, counts or media drive the decision, and record that setting beside every run. For an account activity report, show the number of recent posts actually returned and a coverage warning. Use official permissioned access if the job requires a complete authorized timeline or deeper account data.
Check identity before comparing runs
- Pick a known public handle and define the profile fields and recent-post sample needed for your audit.
- Confirm route access and match the parsed handle. Save the profile counts separately from the posts actually returned.
- Review a few post URLs and any missing fields on the source profile; do not describe the sample as a complete timeline.
- Run a second dated snapshot with the same hydrate setting, then report only the changes supported by parsed fields.
Save a dated account snapshot
Confirm access and identity for one public handle. Save nullable counts and the returned recent-post window.
Get an API keyFAQ
Does this return a full X timeline?
No. It returns the recent posts listed with a public profile, not every post or a date-bounded timeline.
Is hydrate=true always worth the extra cost?
Only when exact recent-post text, counts or media are needed. It is best-effort per post and priced at 1.5× when delivered.
Does profile.verified exist?
No. The public profile contract does not promise a verified field.
Is the X profile example verified live?
No. This article has no authenticated parsed production result for the example handle.






