RedditAPIRedditAPIs
DM

Fetch a Direct Message Thread's Full History

Fetch the complete message history of a single Reddit DM thread with cursor-based pagination — every message, sender, timestamp, and redaction state.

POST/api/reddit/dm/messages$0.025 / call

Fetch the messages inside one DM thread (room). Cursor-based pagination — pass the previous response's next_cursor as before to load older pages, repeat until has_more: false.

Request Body

FieldTypeRequiredDescription
room_idstringyesThread ID from /api/reddit/dm/threads (e.g. !hdsti…:reddit.com)
limitnumbernoMessages per page (default 50, max 100)
beforestringnoCursor from a previous response's next_cursor. Omit for the first page (latest messages).
reddit_sessionstringyesSession cookie from /api/reddit/login
loidstringyesLong-lived account identifier cookie
csrf_tokenstringyesAnti-CSRF cookie

Example

# Page 1 — latest 50 messages
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "room_id": "!hdstiJypyVtzbpoUJZe9mUc-zl-5BnADoRlS7h4itZg:reddit.com",
    "limit": 50,
    "reddit_session": "eyJhbGc...",
    "loid": "000000...",
    "csrf_token": "1c0819..."
  }' \
  "https://api.redditapis.com/api/reddit/dm/messages"

# Page 2 — older messages (use the previous next_cursor)

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
 -d '{
"room_id": "!hdstiJypyVtzbpoUJZe9mUc-zl-5BnADoRlS7h4itZg:reddit.com",
"limit": 50,
"before": "t16_1771566217300",
"reddit_session": "eyJhbGc...",
"loid": "000000...",
"csrf_token": "1c0819..."
}' \
 "https://api.redditapis.com/api/reddit/dm/messages"
async function loadAllMessages(roomId, cookies) {
  const all = [];
  let before = null;
  while (true) {
    const res = await fetch("https://api.redditapis.com/api/reddit/dm/messages", {
      method: "POST",
      headers: {
        Authorization: "Bearer TOKEN",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        room_id: roomId,
        limit: 50,
        before,
        ...cookies,
      }),
    });
    const data = await res.json();
    if (!data.success) throw new Error(data.error);
    all.unshift(...data.messages); // prepend older pages to keep oldest→newest order
    if (!data.has_more) break;
    before = data.next_cursor;
  }
  return all;
}
import requests

def load_all_messages(room_id, cookies, token):
all_msgs = []
before = None
while True:
body = {"room_id": room_id, "limit": 50, \*\*cookies}
if before:
body["before"] = before
r = requests.post(
"https://api.redditapis.com/api/reddit/dm/messages",
json=body,
headers={"Authorization": f"Bearer {token}"},
)
data = r.json()
if not data.get("success"):
raise Exception(data.get("error")) # prepend older pages so the result stays oldest -> newest
all_msgs = data["messages"] + all_msgs
if not data.get("has_more"):
break
before = data["next_cursor"]
return all_msgs

Success Response

{
  "success": true,
  "room_id": "!hdstiJypyVtzbpoUJZe9mUc-zl-5BnADoRlS7h4itZg:reddit.com",
  "message_count": 5,
  "messages": [
    {
      "event_id": "$abcDEF...",
      "body": "Hi",
      "msgtype": "m.text",
      "sender_t2": "t2_284523vyfl",
      "sender_displayname": "henry-gilbert",
      "from_me": false,
      "ts": 1771485811109,
      "date": "2026-02-19T07:23:31.109Z",
      "redacted": false
    },
    {
      "event_id": "$xyzGHI...",
      "body": "Hi",
      "msgtype": "m.text",
      "sender_t2": "t2_xxxxxxxx",
      "sender_displayname": "your_reddit_username",
      "from_me": true,
      "ts": 1771496023456,
      "date": "2026-02-19T10:33:43.456Z",
      "redacted": false
    }
  ],
  "next_cursor": "t16_1771566217300",
  "has_more": true
}

Field Reference

FieldDescription
messagesArray of messages in the page, oldest → newest so the array can be prepended directly when paginating.
messages[].event_idUnique event ID for this message.
messages[].bodyPlain-text content. null if the message was redacted.
messages[].msgtypeMessage type (almost always m.text for DMs).
messages[].sender_t2Sender's t2_* ID.
messages[].sender_displaynameSender's username. May be null in rare cases.
messages[].from_metrue if the authenticated account sent this message.
messages[].redactedtrue if the message was deleted. body will be null.
next_cursorPass back as before to fetch the next (older) page. null when there are no more pages.
has_morefalse when you've reached the start of the conversation.
message_countNumber of messages in this page. May be slightly less than limit when the underlying timeline window contained state events or redactions.

Pagination Notes

  • The first call (no before) returns the latest N messages. Subsequent calls with before: <previous next_cursor> walk backwards in time.
  • Each page is internally ordered oldest → newest. To assemble a full transcript: prepend older pages to the front of your local array (see the JS/Python examples above).
  • has_more: false is the canonical end-of-history signal. Do not rely on next_cursor being null alone — always check has_more.
  • For full-history scraping, batch large limit values (up to 100) to minimise the number of pages.

Errors

StatusMeaning
400Missing room_id or required cookies
401Missing Bearer token
403Invalid Bearer token
502Could not fetch messages (cookies expired or room not accessible)
500Unexpected server error

On this page