# How to get a tweet as JSON without an X API key

Five tested ways to read one public X post as JSON with no developer account: FxTwitter, vxTwitter, syndication, oEmbed and UnifAPI.

- URL: https://unifapi.com/blog/get-tweet-json-without-api-key
- Published: 2026-10-07
- Updated: 2026-10-10
- Category: Cookbooks
- Keywords: tweet json, get tweet json without api key, twitter api without authentication, x post json, fxtwitter api, vxtwitter api, twitter syndication api, tweet to json curl, read tweet programmatically
- Author: Unif Cookbooks team

> In short: you do not need an X developer account to read one public post as JSON. On October 7, 2026 we fetched the same NASA post with `curl` from five places that answer without a key. FxTwitter and vxTwitter return a clean JSON object for a single post or user. X's own syndication endpoint returns the post as JSON too, undocumented and liable to change. X's oEmbed endpoint returns an HTML snippet wrapped in JSON, not data. UnifAPI's `/tools/x/post`, free with no login and rate-limited per visitor, returns the post with author, media, quoted post, and every metric, in the same field names as its search, replies, and timeline endpoints. If you only ever need one post, FxTwitter is enough. If the post is the first step of a workflow that then searches, reads replies, or walks a timeline, use an endpoint whose envelope stays the same for all of those.

The question "how do I get a tweet as JSON" has a different answer than it did in 2022. The official API still works, but the free tier is a token allowance that an agent burns through in an afternoon, and a paid tier starts at a monthly fee most side projects will not justify for a handful of reads. Meanwhile a set of public endpoints grew up around the embed and link-preview use case, and they answer plain HTTP requests with no credentials.

This post is the test we ran before deciding what to build. Every request below is reproducible; copy the command and run it.

## The test

One public post, `https://x.com/NASA/status/2107237881668313108`, fetched with `curl` and a default User-Agent, no cookies, no key. We recorded the status code, the content type, and whether the body contained the post's text and like count as structured fields.

| Endpoint                                                 | Status | Body                                         | Text + metrics as fields   | Media URLs | Quoted post | Also does                                              |
| -------------------------------------------------------- | ------ | -------------------------------------------- | -------------------------- | ---------- | ----------- | ------------------------------------------------------ |
| `api.fxtwitter.com/NASA/status/<id>`                     | 200    | JSON, 3.3 KB                                 | Yes                        | Yes        | Yes         | One user                                               |
| `api.vxtwitter.com/NASA/status/<id>`                     | 200    | JSON, 1.6 KB                                 | Yes                        | Yes        | Yes (URL)   | Nothing else                                           |
| `cdn.syndication.twimg.com/tweet-result?id=<id>&token=x` | 200    | JSON, 3.2 KB                                 | Likes and reply count only | Yes        | Yes         | Nothing else                                           |
| `publish.twitter.com/oembed?url=…`                       | 200    | JSON wrapping HTML                           | No (HTML blockquote)       | No         | No          | Nothing else                                           |
| `unifapi.com/tools/x/post?id=<id>`                       | 200    | JSON, same model as search, replies, profile | Yes                        | Yes        | Yes         | Search, replies, media, followers, trends, communities |

Nothing in that table requires a key. Three of the five give you a usable record of the post. The differences are in what else they can do, how stable they are, and whether you can keep using the same field names when the task grows.

## FxTwitter and vxTwitter: built for link previews, good enough for reads

Both projects exist to make X links unfurl in Discord and Telegram. Their API is a side effect of that, and it is a good one.

```bash
curl -s "https://api.fxtwitter.com/NASA/status/2107237881668313108" | jq '.tweet | {text, likes, retweets, views, created_at}'
```

Returns the text, like, repost, reply, and view counts, the author object, media with sizes and MP4 variants, the quoted post, and a `created_at` timestamp. vxTwitter returns a flatter object with the same essentials and a `mediaURLs` array.

What they do not do: search, replies under a post, a user's timeline, followers. The user endpoint (`api.fxtwitter.com/NASA`) returns counts and the bio but no posts. They also run on volunteer infrastructure with no published rate limit, so a workflow that fans out across hundreds of posts is a guest, not a customer.

## X's syndication endpoint: official, undocumented, fragile

X serves embedded timelines from `cdn.syndication.twimg.com`. The single-post variant answers JSON:

```bash
curl -s "https://cdn.syndication.twimg.com/tweet-result?id=2107237881668313108&token=x" | jq '{text, favorite_count, created_at, user: .user.screen_name}'
```

It is the data X's own embed widget renders, so it is accurate, but it carries only what the widget shows: `favorite_count` and `conversation_count`, no reposts, no views. It is also undocumented, the `token` parameter has changed meaning more than once, and some posts come back as a stub with a `tombstone` instead of the text. Use it as a cross-check, not as a dependency.

## oEmbed: not data

`publish.twitter.com/oembed` is the endpoint CMSs use to embed a post. It returns JSON, but the payload is an HTML `blockquote` with the text inside it and a script tag. There are no metrics and no media URLs. If you want the text, you will be parsing HTML out of JSON, which is the worst of both.

## UnifAPI's free post endpoint

```bash
curl -s "https://unifapi.com/tools/x/post?id=2107237881668313108"
```

```json
{
  "post": {
    "id": "2107237881668313108",
    "text": "Time to bring them home 🌎\n\nAfter nearly eight months aboard the @Space_Station, the four members of Crew-12 will soon head back to Earth…",
    "createdAt": "2026-10-05T22:33:56.000Z",
    "language": "en",
    "url": "https://x.com/NASA/status/2107237881668313108",
    "author": {
      "id": "11348282",
      "handle": "NASA",
      "name": "NASA",
      "verified": true,
      "followers": 92373840
    },
    "metrics": {
      "likes": 7210,
      "reposts": 846,
      "replies": 262,
      "quotes": 60,
      "bookmarks": 197,
      "views": 2823329
    },
    "media": [
      {
        "kind": "photo",
        "url": "https://pbs.twimg.com/media/HT5pcNwXwAAKdoM.jpg",
        "width": 2048,
        "height": 1365
      }
    ],
    "quoted": null
  }
}
```

The `id` parameter also accepts the full `x.com` or `twitter.com` status URL, so an agent can pass through whatever a user pasted. Add `format=md` or send `Accept: text/markdown` to get the same post as Markdown, which is cheaper to put into a model's context than JSON.

Three properties matter for agents:

- **The envelope is shared.** `post`, `author`, `metrics`, and `media` have the same shape on `/tools/x/search`, `/tools/x/replies`, `/tools/x/profile`, and `/tools/x/media`. A prompt that reads `.metrics.likes` on one of them works on all of them.
- **The limit is printed.** Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. The free limit is 20 lookups per 10 minutes per visitor, and a search counts as two; a 429 includes `Retry-After` and the URL where the limit is lifted (the metered [X / Twitter API](/apis/twitter), pay as you go, no subscription).
- **Errors are typed.** A missing or malformed id is `{ "error": { "type": "validation_error", … } }`, a deleted post is `not_found`. An agent can branch on `error.type` without parsing a message.

The full parameter table and a captured sample for every endpoint are on each tool's Markdown page, for example [`/tools/x-post-viewer/index.md`](/tools/x-post-viewer/index.md), and in [`/llms.txt`](/llms.txt).

## Which one to use

- One post, in a bot that unfurls links: FxTwitter. It is what it was built for.
- A cross-check that a post's text is what X serves: the syndication endpoint.
- A post that is step one of something larger (read it, then read its replies, then search for reactions, then look at who replied): the free UnifAPI endpoints, because the next steps exist and share the shape.
- Volume, history beyond the recent window, or guarantees: the metered API with a workspace key. The field names match the free endpoints, so the prompt does not change.

## FAQ

### Do I need a Twitter developer account to read a public tweet?

No. All five endpoints in this post answer without one. The official API is what you need for writing, for private data, and for guaranteed throughput.

### Is scraping x.com directly an option?

Not with curl. `x.com/NASA/status/<id>` returns a 147 KB HTML shell; the post is rendered by JavaScript after the page loads. You would need a headless browser, which is slower, costs more, and breaks when the markup changes.

### Can the UnifAPI endpoint read a protected account's post?

No. Protected and deleted posts return `not_found`. The endpoints read public data only and never bypass X's privacy settings.

### What is the free limit?

20 lookups per 10 minutes per visitor across all `/tools/x/*` endpoints (a search counts as two), reported in the response headers. Using them is free, with no login or account; lifting the limit is pay as you go with a UnifAPI workspace key; there is no free key tier to apply for.
