API and data
Everything Tweetkeep keeps is public, and free to use. No keys, no sign-up. Credit to Tweetkeep with a link is appreciated.
Plain HTTP and standard formats: JSON, Atom, oEmbed, WARC, Memento, OpenTimestamps. All of it over HTTPS at https://tweetkeep.com.
Each address allows 120 requests a minute (IPv6: per /64); past that you get 429 with Retry-After.
Responses say how long they can be cached: please do. For a lot of data, start from the daily files or an account's archive instead of crawling pages.
JSON answers can be read from any website (Access-Control-Allow-Origin: *).
Daily files of deleted and edited tweets
For research: every tweet deleted or edited on X on a given day (UTC), across every account we keep, one JSON object per line (JSON Lines). A day's file appears once the day is over.
GET https://tweetkeep.com/deleted.jsonTry it: https://tweetkeep.com/deleted.json
The list of days: { "days": [{ "day", "deleted", "edited", "file", "internet_archive" }] }, oldest first.
internet_archive is the day's item on archive.org once it's uploaded, with the same file. Cached 1 hour.
GET https://tweetkeep.com/deleted/{YYYY-MM-DD}.jsonlTry it: https://tweetkeep.com/deleted/2026-10-18.jsonl
{ "event": "deleted" | "edited", "at", "handle", "id", "url", "kind", "created_at", "text", "edited_at", "edited_text", "deleted_at",
"likes", "reposts", "replies", "quotes", "views", "media", "snapshots", "top_reply", "community_note", "proof" }
One line per event, oldest first. A tweet edited and deleted on the same day has two lines. The fields after handle are a post as in an
account archive, as it stands now. Days with nothing deleted or edited have no file (404). Cached 1 day.
curl -s https://tweetkeep.com/deleted.json | jq -r '.days[].file' | xargs -n1 curl -sOAccount archive (JSON)
Everything we keep for one account: its profile over time, its suspensions and every post, with links to our copies of its media and snapshots and to each post's proof.
GET https://tweetkeep.com/@{handle}/archive.jsonTry it: https://tweetkeep.com/@MarioNawfal/archive.json
{ "account": { "handle", "name", "x_id", "status", "archive" },
"exported_at": "2026-10-19T18:00:00.000Z",
"profile_history": [{ "at", "name", "bio", "url", "location", "avatar", "pinned" }],
"suspensions": [{ "reason", "from", "to" }],
"posts": [{ "id", "url", "kind", "created_at", "text", "reply_to_id", "edited_at", "edited_text", "deleted_at",
"likes", "reposts", "replies", "quotes", "views", "media": [{ "type", "file", "original", "video" }],
"snapshots", "top_reply": { "id", "handle", "name", "created_at", "text", "likes", "reposts", "media", … },
"community_note": { "id", "title", "text", "at" }, "proof" }] }
Times are ISO 8601, UTC. kind is post, reply, quote or retweet. Cached 10 minutes. Accounts on the waitlist have none (404).
Deleted and edited tweets (Atom feeds)
The 50 latest tweets deleted or edited on X, newest change first, for feed readers ("RSS") and newsroom alerts. Each entry links to the tweet's page here and carries its text (and, for an edit, what it says now).
GET https://tweetkeep.com/deleted.atomTry it: https://tweetkeep.com/deleted.atom
GET https://tweetkeep.com/@{handle}/deleted.atomTry it: https://tweetkeep.com/@MarioNawfal/deleted.atom
Atom 1.0. An entry's id ends in #deleted or #edited; updated is when it happened. Cached 10 minutes.
Embeds (oEmbed)
Show an archived tweet on your site. Paste a tweet page's link (https://tweetkeep.com/p/{id}) into WordPress or any site that reads oEmbed,
or ask for the code yourself:
GET https://tweetkeep.com/oembed?url={tweet page}&maxwidth=550Try it: https://tweetkeep.com/oembed?url=https%3A%2F%2Ftweetkeep.com%2Fp%2F2111143164673482754
{ "version": "1.0", "type": "rich", "provider_name": "Tweetkeep", "title", "author_name", "author_url",
"html": "<iframe src="https://tweetkeep.com/p/{id}/embed" width="550" height="…" …></iframe>", "width", "height", "cache_age": 3600 }
url must be one of our tweet pages; maxwidth 250 to 550; JSON only (format=xml answers 501). The iframe page,
/p/{id}/embed, is the one page other sites may frame: no scripts, and links open here in a new tab. Every tweet page says where its oEmbed is
(<link rel="alternate" type="application/json+oembed">) and offers the code.
Proofs
Every tweet's text, every edit and every snapshot is fingerprinted (SHA-256) when we save it; every hour the new fingerprints go into a list, and the list is timestamped in Bitcoin with OpenTimestamps. See how to check one.
GET https://tweetkeep.com/proof/{id}Try it: https://tweetkeep.com/proof/2111143164673482754
The receipt, as plain text: each fingerprint, the file it's of, the list it's in, and X's raw data (WARC) for the tweet.
GET https://tweetkeep.com/proof/{id}/textTry it: https://tweetkeep.com/proof/2111143164673482754/text
The exact bytes fingerprinted for the text: the tweet ID, a newline, the text (UTF-8). /proof/{id}/edit: the same for an edit.
GET https://tweetkeep.com/data/proofs/{list}.txtTry it: https://tweetkeep.com/data/proofs/2026-10-19T1847.txt
A list (named for when it was made, UTC): one line per fingerprint, {post IDs} {text|edit|snap|warc} {sha256} {file}.
Never changes. Its .txt.ots is its OpenTimestamps proof: pending at first, it gains its Bitcoin path a few hours later (cached 1 hour).
Check it with ots verify or at opentimestamps.org.
X's raw data (WARC)
Every response X sent our browser for a tweet (its page, the timelines it was in), exactly as it came, as a WARC record (ISO 28500): open it with any WARC tool, such as ReplayWeb.page or warcio. The requests aren't kept.
GET https://tweetkeep.com/warc/{record}.warc.gzTry it: https://tweetkeep.com/warc/273.warc.gz
A gzipped WARC file with one response record. Its SHA-256 (of the file as served) is in the hourly list, and a tweet's receipt lists every record it's in.
Records never change. Each finished day's records and lists also go to the Internet Archive as one item, tweetkeep-archive-{day}.
Memento (RFC 7089)
Ask for a tweet the way web archives answer: by its X link, x.com or twitter.com, any form.
GET https://tweetkeep.com/timemap/link/{tweet link}Try it: https://tweetkeep.com/timemap/link/https://x.com/MarioNawfal/status/2111143164673482754
Every copy we hold, in link format: the tweet as we first archived it, then each snapshot of its page.
GET https://tweetkeep.com/timegate/{tweet link}Try it: https://tweetkeep.com/timegate/https://x.com/MarioNawfal/status/2111143164673482754
Redirects (302) to the copy closest to the Accept-Datetime header (an HTTP date), or to the latest without one. Vary: accept-datetime.
GET https://tweetkeep.com/web/{YYYYMMDDhhmmss}/{tweet link}Try it: https://tweetkeep.com/timegate/https://x.com/MarioNawfal/status/2111143164673482754
A copy, with Memento-Datetime and Link (original, timegate, timemap) headers. Snapshot images carry the same headers.
curl -I -H 'Accept-Datetime: Mon, 19 Oct 2026 12:00:00 GMT' https://tweetkeep.com/timegate/https://x.com/MarioNawfal/status/2111143164673482754Search
Search what archived tweets say. The page's address is stable to link to; /search.json answers the same search for scripts.
GET https://tweetkeep.com/search?q={words}&account=&only=&kind=&since=&until=&sort=&page=Try it: https://tweetkeep.com/search?q=ceasefire
GET https://tweetkeep.com/search.json?q={words}&…Try it: https://tweetkeep.com/search.json?q=ceasefire&only=deleted
{ "query", "mode": "words" | "text" | "close", "total", "page", "pages",
"results": [{ "id", "handle", "url", "page", "kind", "created_at", "text", "edited_at", "edited_text", "deleted_at", "likes", "proof" }] }
q- An
@handle, a tweet link or ID, or words:"exact phrase",-wordto leave one out,orbetween alternatives. With symbols ($SOL,#tag, a link) it matches that exact text. account- A monitored account's handle.
onlydeletedoredited.kindpostsorreplies.since,until- Dates,
YYYY-MM-DD(until is inclusive). sortnewestorlikes(default: best match).page- 20 a page, up to 50 pages.
30 searches a minute per address, the page and JSON together; past that, 429. mode says how q was read:
words (ranked), exact text (it has symbols), or close matches (no post had the words). /search.json only searches tweets: an @handle is text there,
and q is required (400 without). Cached 5 minutes.
Sitemap and llms.txt
/sitemap.xml lists every public account and every tweet with a page of its own (deleted, edited or saved). /llms.txt describes the site for language models. /robots.txt says what not to crawl.
Not an API
These serve our own pages and may change without notice: /events and /events/older (the live feed),
/search/popular (our pages only), /check, /votes and /vote, /add, /save, /admin.