Skip to main content
GET
/
x
/
bookmarks
Get bookmarks
curl --request GET \
  --url https://xquik.com/api/v1/x/bookmarks \
  --header 'x-api-key: <api-key>'
import requests

url = "https://xquik.com/api/v1/x/bookmarks"

headers = {"x-api-key": "<api-key>"}

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

print(response.text)
const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};

fetch('https://xquik.com/api/v1/x/bookmarks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
package main

import (
"fmt"
"net/http"
"io"
)

func main() {

url := "https://xquik.com/api/v1/x/bookmarks"

req, _ := http.NewRequest("GET", url, nil)

req.Header.Add("x-api-key", "<api-key>")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
Requested result counts are upper bounds for paid authenticated calls. When remaining credits cannot cover the full page or ID list, Xquik returns fewer results. If zero paid results are affordable, it returns 402 insufficient_credits.
1 credit per result returned · All plans from $0.00012/credit
Requires a connected X account. Uses user-authenticated access.
curl -G https://xquik.com/api/v1/x/bookmarks \
  -H "x-api-key: xq_YOUR_KEY_HERE" | jq

# Page 2
curl -G https://xquik.com/api/v1/x/bookmarks \
  --data-urlencode "cursor=abc123" \
  -H "x-api-key: xq_YOUR_KEY_HERE" | jq
const bookmarkFolderId = ""; // Set to a folder ID to export one folder.
const baseUrl = "https://xquik.com/api/v1/x/bookmarks";
let pageCursor = "";

for (let pageIndex = 0; pageIndex < 3; pageIndex += 1) {
  const params = new URLSearchParams();
  if (bookmarkFolderId !== "") params.set("folderId", bookmarkFolderId);
  if (pageCursor !== "") params.set("cursor", pageCursor);

  const query = params.toString();
  const response = await fetch(query === "" ? baseUrl : `${baseUrl}?${query}`, {
    headers: { "x-api-key": "xq_YOUR_KEY_HERE" },
  });
  const page = await response.json();
  if (!response.ok) throw new Error(JSON.stringify(page));

  const bookmarkRows = page.tweets.map((tweet) => ({
    bookmark_source: bookmarkFolderId === "" ? "all_bookmarks" : "folder",
    folder_id: bookmarkFolderId || null,
    tweet_id: tweet.id,
    tweet_url: tweet.url ?? null,
    text: tweet.text,
    author_id: tweet.author?.id ?? null,
    author_username: tweet.author?.username ?? null,
    author_name: tweet.author?.name ?? null,
    author_followers: tweet.author?.followers ?? null,
    author_verified: tweet.author?.verified ?? null,
    author_profile_picture: tweet.author?.profilePicture ?? null,
    created_at: tweet.createdAt ?? null,
    like_count: tweet.likeCount ?? null,
    reply_count: tweet.replyCount ?? null,
    retweet_count: tweet.retweetCount ?? null,
    quote_count: tweet.quoteCount ?? null,
    view_count: tweet.viewCount ?? null,
    media_urls: (tweet.media ?? []).map((item) => item.mediaUrl).filter(Boolean),
    page_index: pageIndex,
    page_cursor: pageCursor,
    next_cursor: page.next_cursor,
    has_next_page: page.has_next_page,
  }));
  for (const row of bookmarkRows) process.stdout.write(`${JSON.stringify(row)}\n`);

  if (!page.has_next_page || page.next_cursor === "") break;
  pageCursor = page.next_cursor;
}
import json
import requests

bookmark_folder_id = ""  # Set to a folder ID to export one folder.
page_cursor = ""

for page_index in range(3):
    params = {}
    if bookmark_folder_id:
        params["folderId"] = bookmark_folder_id
    if page_cursor:
        params["cursor"] = page_cursor

    response = requests.get(
        "https://xquik.com/api/v1/x/bookmarks",
        params=params,
        headers={"x-api-key": "xq_YOUR_KEY_HERE"},
    )
    page = response.json()
    if not response.ok:
        raise RuntimeError(page)

    for tweet in page["tweets"]:
        bookmark_row = {
            "bookmark_source": "all_bookmarks" if not bookmark_folder_id else "folder",
            "folder_id": bookmark_folder_id or None,
            "tweet_id": tweet["id"],
            "tweet_url": tweet.get("url"),
            "text": tweet["text"],
            "author_id": (tweet.get("author") or {}).get("id"),
            "author_username": (tweet.get("author") or {}).get("username"),
            "author_name": (tweet.get("author") or {}).get("name"),
            "author_followers": (tweet.get("author") or {}).get("followers"),
            "author_verified": (tweet.get("author") or {}).get("verified"),
            "author_profile_picture": (tweet.get("author") or {}).get("profilePicture"),
            "created_at": tweet.get("createdAt"),
            "like_count": tweet.get("likeCount"),
            "reply_count": tweet.get("replyCount"),
            "retweet_count": tweet.get("retweetCount"),
            "quote_count": tweet.get("quoteCount"),
            "view_count": tweet.get("viewCount"),
            "media_urls": [
                item["mediaUrl"] for item in tweet.get("media", []) if item.get("mediaUrl")
            ],
            "page_index": page_index,
            "page_cursor": page_cursor,
            "next_cursor": page["next_cursor"],
            "has_next_page": page["has_next_page"],
        }
        print(json.dumps(bookmark_row, separators=(",", ":")))

    if not page["has_next_page"] or not page["next_cursor"]:
        break
    page_cursor = page["next_cursor"]

Bookmarks handoff

Use GET /x/bookmarks when a reading list, CRM, research queue, or agent needs saved tweets from the authenticated account. The examples write JSON Lines rows with bookmark source, folder ID, tweet ID, tweet URL, text, author ID, username, display name, follower count, verified state, profile image URL, engagement counts, media URLs, and cursor fields. Store the last saved next_cursor per folder so each bookmark export can resume without duplicating earlier rows.

All saved tweets

Omit folderId when the workflow needs every bookmarked tweet visible to the connected account.

Folder export

Call Bookmark Folders first, then pass its folder_id as folderId.

Cursor checkpoint

Store has_next_page and next_cursor per folder. Pass next_cursor back as cursor only when has_next_page is true.

Account-scoped queue

Keep saved-tweet rows in account-scoped research, CRM, or agent memory systems.

Query parameters

folderId
string
Bookmark folder ID. Omit to return all bookmarks.
cursor
string
Pagination cursor. Pass the next_cursor value from the previous response to fetch the next page.

Which saved-feed endpoint?

Saved tweets

Use GET /x/bookmarks for bookmarked tweets from the connected account.

Bookmark folders

Use GET /x/bookmarks/folders to find folder IDs before a folder-specific bookmark export.

Home timeline

Use GET /x/timeline for the connected account’s home feed instead of saved tweets.

Notifications

Use GET /x/notifications for inbox activity rows from the connected account.

Headers

x-api-key
string
required
Your API key. Session cookie authentication is also supported.

Response

tweets
object[]
Array of bookmarked tweets.
has_next_page
boolean
Whether more results are available.
next_cursor
string
Opaque cursor for the next page. Empty string when no more results.
{
  "tweets": [
    {
      "id": "1893456789012345678",
      "text": "Bookmarked tweet content",
      "createdAt": "2026-02-24T10:00:00.000Z",
      "likeCount": 150,
      "retweetCount": 42,
      "replyCount": 10,
      "url": "https://x.com/user/status/1893456789012345678",
      "author": {
        "id": "44196397",
        "username": "elonmusk",
        "name": "Elon Musk",
        "followers": 150000000,
        "verified": true,
        "profilePicture": "https://pbs.twimg.com/profile_images/example.jpg"
      }
    }
  ],
  "has_next_page": true,
  "next_cursor": "DAADDAABCgABF..."
}
Last modified on June 14, 2026