What an X Profile API Snapshot Can Tell You About a Public Account

By Anurag Pathak, Founder of Serpent API·

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 inputUseInterpretation check
handle, name, bio, websiteCapture identity and profile context.No verified badge field is promised on the profile.
counts.followers, following, postsKeep nullable stated counts.Null is unknown, not zero.
recent_posts[].id, url, text, created_atRecord returned recent-post sample.The array is not a full timeline.
hydrated post counts, mediaRead 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

OptionBest useAccess or billing unitDecision
Official X developer platformDirect 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 basePublic 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 hydratedExact 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 changeSafe findingCheck first
Bio or website changed on matched identityDifferent values in two dated snapshotsOpen the profile for current context.
Follower counts differ and both are numericTwo observed countsDo not assign a cause to the movement.
Recent post absent from later short listNot returned in the later sampleOpen its URL; do not declare deletion.
Hydrated detail missing on one postThat post's detail is unknownDo 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

  1. Pick a known public handle and define the profile fields and recent-post sample needed for your audit.
  2. Confirm route access and match the parsed handle. Save the profile counts separately from the posts actually returned.
  3. Review a few post URLs and any missing fields on the source profile; do not describe the sample as a complete timeline.
  4. 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 key

Try the playground · Read the field contract

FAQ

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.

Related Posts