---
title: "Get Article (v2) - API Reference"
description: "API endpoint returning a Twitter/X article as ready-to-use Markdown instead of a raw Draft.js tree. Flat-rate pricing of $0.0002 per request."
source: "https://docs.socialdata.tools/reference/get-article-v2/"
---

Returns a Twitter/X article rendered as **Markdown**, ready to store, index or feed to an LLM.

The [Get article](https://docs.socialdata.tools/reference/get-tweet-article/) endpoint returns the article body as `content_state`, X’s raw Draft.js document tree — a nested structure of blocks and entity ranges you have to walk yourself. This endpoint renders that tree for you and returns the result as a Markdown string in `markdown`, dropping `content_state` and `media_entities` from the response. Everything else is the same tweet object the other endpoints return.

Headings, bold and italic text, ordered and unordered lists, blockquotes, images, dividers, links, code blocks and emoji are all preserved. Embedded posts become links.

## Not every “article” ID is an article

Long ordinary posts and articles look similar and are easy to confuse — roughly **15% of the requests we see on this endpoint are ordinary long posts**, not articles. Rather than failing those, this endpoint renders the post’s own text as Markdown and tells you which happened:

| `markdown_source` | Meaning | `article` |
| --- | --- | --- |
| `article` | The ID is a real article. `markdown` is the rendered article body. | Metadata object |
| `tweet_text` | The ID is an ordinary post. `markdown` is the post’s own text, rendered. | `null` |

Both outcomes return `200` and both are billed the same. Branch on `markdown_source` rather than assuming.

> **markdown\_source, not source**
> 
> The field is **`markdown_source`**. The tweet object has its own unrelated `source` field, which holds the client the post was sent from — for example `<a href="...">Twitter for iPhone</a>`. They are different fields; do not confuse them.

GET https://api.socialdata.tools/v2/twitter/article/{article\_id}

## Headers

**Authorization** `string` — required

Authorization Bearer header containing your SocialData API key

Example: Bearer YOUR\_API\_KEY

## Parameters

**article\_id** `integer` — required

The numerical ID of the post carrying the article. This is the ID of the post itself, not the ID in an x.com/i/article/... URL.

Example: 2084992645966016757

> **Caution**
> 
> When using languages where the `article_id` value exceeds the default Integer type limit (e.g., JavaScript), you should store `article_id` as a String. Use the `id_str` property returned by the API for these values

## Response Fields

In addition to the standard tweet object fields, the response contains:

| Field | Type | Description |
| --- | --- | --- |
| `markdown` | string | The article body rendered as Markdown, or the post’s own text when `markdown_source` is `tweet_text`. |
| `markdown_source` | string | Either `article` or `tweet_text`. See above. |
| `article` | object | null | Article metadata: `id`, `id_str`, `title`, `preview_text`, `cover_url`, `published_at`. `null` when `markdown_source` is `tweet_text`. |

Note that `article` here does **not** contain `content_state` or `media_entities`. Use [Get article](https://docs.socialdata.tools/reference/get-tweet-article/) if you need the raw Draft.js tree.

## Code Examples

#### curl

```shellscript
curl "https://api.socialdata.tools/v2/twitter/article/2084992645966016757" \
    -H 'Authorization: Bearer API_KEY' \
    -H 'Accept: application/json'
```

#### JavaScript

```js
const articleId = '2084992645966016757';
const API_KEY = 'YOUR_API_KEY_HERE';

fetch(`https://api.socialdata.tools/v2/twitter/article/${articleId}`, {
    method: 'GET',
    headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Accept': 'application/json'
    }
})
.then(response => response.json())
.then(response => {
    if (response.markdown_source === 'article') {
        console.log(response.article.title);
    }
    console.log(response.markdown);
})
.catch(err => console.error(err));
```

#### Python

```python
import requests

articleId = '2084992645966016757'
API_KEY = 'YOUR_API_KEY_HERE'

url = f'https://api.socialdata.tools/v2/twitter/article/{articleId}'

headers = {
    'Authorization': f'Bearer {API_KEY}',
    'Accept': 'application/json'
}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    data = response.json()

    if data['markdown_source'] == 'article':
        print(data['article']['title'])

    print(data['markdown'])
else:
    print(f"Error: {response.status_code}")
    print(response.text)
```

#### PHP

```php
$articleId = '2084992645966016757';
$API_KEY = 'YOUR_API_KEY_HERE';

$url = "https://api.socialdata.tools/v2/twitter/article/{$articleId}";

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer $API_KEY",
        "Accept: application/json"
    ]
]);

$response = curl_exec($ch);
$data = json_decode($response, true);

if ($data['markdown_source'] === 'article') {
    echo $data['article']['title'], PHP_EOL;
}

echo $data['markdown'], PHP_EOL;

curl_close($ch);
```

## Example Responses

The `markdown` value in the `200 (article)` example below is truncated, and its `entities` object emptied, to keep the example readable — a real response carries the whole article and the full tweet object.

#### 200 (article)

```json
{
  "tweet_created_at": "2026-08-05T13:19:18.000000Z",
  "id": 2084992645966016757,
  "id_str": "2084992645966016757",
  "type": "tweet",
  "conversation_id_str": "2084992645966016757",
  "community_id_str": null,
  "community_name": null,
  "text": null,
  "full_text": "https://t.co/Cavlnc29qI",
  "source": "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>",
  "truncated": false,
  "in_reply_to_status_id": null,
  "in_reply_to_status_id_str": null,
  "in_reply_to_user_id": null,
  "in_reply_to_user_id_str": null,
  "in_reply_to_screen_name": null,
  "user": {
    "id": 703601972,
    "id_str": "703601972",
    "name": "Akshay 🚀",
    "screen_name": "akshay_pachaar",
    "location": "Learn AI Engineering 👉",
    "url": "http://join.dailydoseofds.com",
    "description": "Simplifying LLMs, AI Agents, RAG, and Machine Learning for you! • Co-founder @dailydoseofds_• BITS Pilani • 3 Patents • ex-AI Engineer @ LightningAI",
    "protected": false,
    "verified": true,
    "followers_count": 283837,
    "friends_count": 497,
    "listed_count": 3635,
    "favourites_count": 22793,
    "statuses_count": 21273,
    "created_at": "2012-07-18T18:58:39.000000Z",
    "profile_banner_url": "https://pbs.twimg.com/profile_banners/703601972/1733646485",
    "profile_image_url_https": "https://pbs.twimg.com/profile_images/1578327351544360960/YFpWSWIX_normal.jpg",
    "can_dm": true,
    "affiliation_label": null
  },
  "quoted_status_id": null,
  "quoted_status_id_str": null,
  "is_quote_status": false,
  "quoted_status": null,
  "retweeted_status": null,
  "quote_count": 0,
  "reply_count": 6,
  "retweet_count": 18,
  "favorite_count": 182,
  "views_count": 28824,
  "bookmark_count": 248,
  "lang": "zxx",
  "entities": {
    "hashtags": [],
    "symbols": [],
    "urls": [],
    "user_mentions": []
  },
  "is_pinned": false,
  "article": {
    "published_at": "2026-08-05T13:19:18.000000Z",
    "id": 2084992645966016757,
    "id_str": "2084992645966016757",
    "title": "How to serve 5 models on one GPU (100% open-source)",
    "preview_text": "A real AI pipeline rarely runs on a single model. This article shows how to serve an SLM, an OCR model, an NER model, a reranker, and an object detector, through a serving layer on a single GPU.",
    "cover_url": "https://pbs.twimg.com/media/HO9edfxbEAAxTFy.jpg"
  },
  "markdown": "A real AI pipeline rarely runs on a single model. This article shows how to serve an SLM, an OCR model, an NER model, a reranker, and an object detector, through a serving layer on a single GPU.\n\n---\n\nSmall models are changing how AI systems are built.\n\nProduction AI systems are moving from a single large model doing everything to several smaller models, each doing one job.\n\nOne parses the document, the next extracts fields, a third reranks search results, a vision model reads the image, and a final model handles generation.\n\nAt the model level, this usually brings the cost down quite a bit.\n\nBut the model is only part of the inference bill. You still need GPUs to run it, memory to keep it loaded, and a serving layer to batch and schedule the requests coming through it.\n\nIf you don't want to operate that infrastructure yourself, you can push it onto a managed provider.\n\n![](https://pbs.twimg.com/media/HO9Q3_saYAE5rG0.jpg)\n\nThat works well when you want to get started quickly, but the bill grows as your cost is tied to provider usage. And you give up control over which models you can run and where your data goes.\n\nFor teams that need greater control over models, data, and infrastructure, self-hosting is the natural choice.\n\nAlthough one small model is easy enough to accommodate in self-hosting. But a real business problem rarely stops at one.\n\nSpecialized models are designed to do one narrow thing well. You need several models, each handling its own piece of the work, stitched together into one business pipeline.\n\nNow the infrastructure has to keep all of those models available and serve them.\n\nYou saved money by moving to smaller models. The way you serve them can give that saving back.\n\nToday, we understand why that is the case and what serving small models well actually takes.\n\n## How to Read This\n\nTwo halves: how GPU serving actually works, then the pipeline running end to end.\n\nWant the code? Skip to Proving It Against a Real Document. The five calls run standalone.\n\nBut the first half is the part you can reuse anywhere. Memory allocation, batching and padding waste, queue isolation, load and evict policy: these are the parameters that decide your GPU bill, whatever engine you end up running. Knowing them is the difference between picking a serving stack and inheriting one.\n\nNote that sharing a GPU does not mean five models resident at once. Models load on demand and get evicted when memory runs short.\n\nWhat's ahead:\n\n- **Serving Tools in a Multi-Model Pipeline.** What vLLM and TEI each solve, and why five stages fragment across three servers.\n- **The Problem with Standard Serving Tools.** Dedicated or shared GPUs, idle time you pay for, and the memory knobs that decide it.\n- **What a Serving Stack for Small Models Needs.** The four requirements, before naming any tool.\n\n...(this example is truncated for brevity; the real response contains the whole article)",
  "markdown_source": "article"
}
```

#### 200 (tweet\_text)

```json
{
  "tweet_created_at": "2026-06-22T13:01:42.000000Z",
  "id": 2069043150891663371,
  "id_str": "2069043150891663371",
  "type": "tweet",
  "conversation_id_str": "2069043150891663371",
  "community_id_str": null,
  "community_name": null,
  "text": null,
  "full_text": "Native USDC, EURC, and CCTP are coming soon to @Cronosapp.\n\nWe’re bringing the leading stablecoins, CCTP, and Circle Mint to Cronos to power prediction markets, trading, payments, treasury management, and agentic workflows.\n\nKey benefits of native @USDC and EURC:\n→ Redeem 1:1 for USD and EUR, respectively\n→ MiCA-compliant and fully reserved\n→ Integrate seamlessly with Cronos apps and DeFi protocols\n→ Unlock dollar- and euro-denominated crosschain infrastructure on Cronos\n\nCCTP enables smooth USDC crosschain transfers without third-party bridges while Circle Mint adds institutional access to fiat on/offramps, deposits, withdrawals, transfers, and API connectivity for eligible users.\n\nLearn more:\nhttps://t.co/oAx2yQBW2K",
  "source": "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>",
  "truncated": false,
  "in_reply_to_status_id": null,
  "in_reply_to_status_id_str": null,
  "in_reply_to_user_id": null,
  "in_reply_to_user_id_str": null,
  "in_reply_to_screen_name": null,
  "user": {
    "id": 2151686839,
    "id_str": "2151686839",
    "name": "Circle",
    "screen_name": "circle",
    "location": "Remote First",
    "url": "http://circle.com",
    "description": "The full-stack platform for the internet financial system. Making the economy open to all. Disclosure: https://t.co/7L62d1qjty",
    "protected": false,
    "verified": true,
    "followers_count": 282350,
    "friends_count": 461,
    "listed_count": 2611,
    "favourites_count": 4365,
    "statuses_count": 7166,
    "created_at": "2013-10-23T21:10:31.000000Z",
    "profile_banner_url": "https://pbs.twimg.com/profile_banners/2151686839/1760733158",
    "profile_image_url_https": "https://pbs.twimg.com/profile_images/1719446730091962368/Bl01sQsB_normal.png",
    "can_dm": false,
    "affiliation_label": null,
    "verification_info": {
      "type": "Business"
    }
  },
  "quoted_status_id": null,
  "quoted_status_id_str": null,
  "is_quote_status": false,
  "quoted_status": null,
  "retweeted_status": null,
  "quote_count": 12,
  "reply_count": 73,
  "retweet_count": 133,
  "favorite_count": 573,
  "views_count": 39649,
  "bookmark_count": 17,
  "lang": "en",
  "entities": {
    "media": [
      {
        "display_url": "pic.x.com/6uMmARTRRj",
        "expanded_url": "https://x.com/circle/status/2069043150891663371/photo/1",
        "ext_media_availability": {
          "status": "Available"
        },
        "features": {
          "large": {
            "faces": []
          },
          "medium": {
            "faces": []
          },
          "orig": {
            "faces": []
          },
          "small": {
            "faces": []
          }
        },
        "id_str": "2069043147724959744",
        "indices": [
          277,
          300
        ],
        "media_key": "3_2069043147724959744",
        "media_results": {
          "result": {
            "media_key": "3_2069043147724959744"
          }
        },
        "media_url_https": "https://pbs.twimg.com/media/HLa3x9UaMAA9Jpa.jpg",
        "original_info": {
          "focus_rects": [
            {
              "h": 630,
              "w": 1125,
              "x": 0,
              "y": 0
            },
            {
              "h": 630,
              "w": 630,
              "x": 0,
              "y": 0
            },
            {
              "h": 630,
              "w": 553,
              "x": 0,
              "y": 0
            },
            {
              "h": 630,
              "w": 315,
              "x": 53,
              "y": 0
            },
            {
              "h": 630,
              "w": 1200,
              "x": 0,
              "y": 0
            }
          ],
          "height": 630,
          "width": 1200
        },
        "sizes": {
          "large": {
            "h": 630,
            "resize": "fit",
            "w": 1200
          },
          "medium": {
            "h": 630,
            "resize": "fit",
            "w": 1200
          },
          "small": {
            "h": 357,
            "resize": "fit",
            "w": 680
          },
          "thumb": {
            "h": 150,
            "resize": "crop",
            "w": 150
          }
        },
        "type": "photo",
        "url": "https://t.co/6uMmARTRRj"
      }
    ],
    "user_mentions": [
      {
        "id_str": "1411867326828335107",
        "indices": [
          47,
          57
        ],
        "name": "Cronos",
        "screen_name": "Cronosapp"
      },
      {
        "id_str": "1819490209643270144",
        "indices": [
          248,
          253
        ],
        "name": "USDC",
        "screen_name": "USDC"
      }
    ],
    "hashtags": [],
    "symbols": [],
    "urls": [
      {
        "display_url": "circle.com/blog/usdc-eurc…",
        "expanded_url": "http://www.circle.com/blog/usdc-eurc-and-cctp-are-coming-soon-to-cronos-what-you-need-to-know",
        "indices": [
          704,
          727
        ],
        "url": "https://t.co/oAx2yQBW2K"
      }
    ],
    "display_text_range": [
      0,
      276
    ]
  },
  "is_pinned": false,
  "article": null,
  "markdown": "Native USDC, EURC, and CCTP are coming soon to [@Cronosapp](https://x.com/Cronosapp).\n\nWe’re bringing the leading stablecoins, CCTP, and Circle Mint to Cronos to power prediction markets, trading, payments, treasury management, and agentic workflows.\n\nKey benefits of native [@USDC](https://x.com/USDC) and EURC:\n→ Redeem 1:1 for USD and EUR, respectively\n→ MiCA-compliant and fully reserved\n→ Integrate seamlessly with Cronos apps and DeFi protocols\n→ Unlock dollar- and euro-denominated crosschain infrastructure on Cronos\n\nCCTP enables smooth USDC crosschain transfers without third-party bridges while Circle Mint adds institutional access to fiat on/offramps, deposits, withdrawals, transfers, and API connectivity for eligible users.\n\nLearn more:\n[circle.com/blog/usdc-eurc…](http://www.circle.com/blog/usdc-eurc-and-cctp-are-coming-soon-to-cronos-what-you-need-to-know)",
  "markdown_source": "tweet_text"
}
```

#### 402

```json
{
    "status": "error",
    "message": "Insufficient balance"
}
```

#### 404

```json
{
    "status": "error",
    "message": "Tweet not found"
}
```

#### 500

```json
{
    "status": "error",
    "message": "Failed to fetch data from Twitter"
}
```

## Response Codes

-   **200 OK** - request succeeded
-   **402 Payment Required** - not enough credits to perform this request
-   **404 Not Found** - requested tweet does not exist
-   **422 Unprocessable Content** - validation failed (e.g. one of the required parameters was not provided)
-   **500 Internal Error** - API internal error, typically means that SocialData API failed to obtain the requested information and you should try again later

## Before you integrate

-   [Authentication](https://docs.socialdata.tools/getting-started/authentication/)
-   [Rate limits](https://docs.socialdata.tools/getting-started/rate-limits/)
-   [Errors](https://docs.socialdata.tools/getting-started/errors/)
-   [Pricing](https://docs.socialdata.tools/getting-started/pricing/)
