
# Search X posts with Python, Node.js and cURL

Search public X (Twitter) posts by keyword and print who posted each one, its likes and its link. X search operators work in `query`: here, NASA's posts with media.

It is one call to [`POST /v1/x/search`](/reference/x/searchX), which costs 1 credit a request, plus 1 per post. Every snippet below ran against the live API on 27 October 2026, and the output is what the Python printed.

Set your key first. Create one at https://weirapp.io/dashboard/keys; every account gets 5,000 free credits a month.

```bash
export WEIR_API_KEY=weir_live_...
```

## Python

```python
import os

import requests

response = requests.post(
    "https://api.weirapp.io/v1/x/search",
    headers={"Authorization": f"Bearer {os.environ['WEIR_API_KEY']}"},
    json={"query": "from:NASA filter:media", "limit": 5},
    timeout=60,
)
response.raise_for_status()
page = response.json()

for post in page["data"]:
    print(post["author"]["username"], post["likeCount"], post["url"])
print("credits charged:", response.headers["X-Credits-Charged"])
```

## Node.js

```js
// Node.js 18 or later, as an ES module (save as example.mjs).
const response = await fetch("https://api.weirapp.io/v1/x/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WEIR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ query: "from:NASA filter:media", limit: 5 }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const page = await response.json();

for (const post of page.data) console.log(post.author.username, post.likeCount, post.url);
console.log("credits charged:", response.headers.get("x-credits-charged"));
```

## cURL

```bash
curl --request POST \
  --url 'https://api.weirapp.io/v1/x/search' \
  --header "Authorization: Bearer $WEIR_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"query":"from:NASA filter:media","limit":5}'
```

## Output

```text
NASA 14 https://x.com/NASA/status/2114832256476872993
NASA 4108 https://x.com/NASA/status/2114801524358406570
NASA 7542 https://x.com/NASA/status/2114484649430798432
NASA 7777 https://x.com/NASA/status/2113776971603689874
NASA 8583 https://x.com/NASA/status/2113655288687431819
credits charged: 6
```

## The next page

A page ends with `meta.nextCursor`. Send it back as `cursor`, with every other parameter unchanged, until it is `null`. Each page is its own request and is charged as one.

```python
import os

import requests

headers = {"Authorization": f"Bearer {os.environ['WEIR_API_KEY']}"}
cursor = None
for number in range(1, 3):  # two pages; each page is its own charged request
    response = requests.post(
        "https://api.weirapp.io/v1/x/search",
        headers=headers,
        json={"query": "from:NASA filter:media", "limit": 5, **({"cursor": cursor} if cursor else {})},
        timeout=60,
    )
    response.raise_for_status()
    page = response.json()
    print(f"page {number}: {len(page['data'])} posts, {response.headers['X-Credits-Charged']} credits")
    cursor = page["meta"]["nextCursor"]
    if not cursor:  # null means there is nothing more
        break
```

```text
page 1: 5 posts, 6 credits
page 2: 5 posts, 6 credits
```

## If a call fails

Failed calls are free. A `429` means too many requests a minute: wait the seconds in `Retry-After` and send it again. A `402` means the account is out of credits. A `503` means the source is busy and is safe to retry. Every code is on [Errors](/errors), and paging is on [Pagination](/pagination).
