Der Aufbau einer Reddit-Integration, die private Nachrichten verarbeitet, erfordert das Verständnis von Reddits einzigartigem Ansatz für Messaging. Das reddit api messages-System verwendet eine Kombination aus Inbox-Endpoints, Fullname-Identifikatoren und OAuth-Scopes, die sich von typischen Messaging-APIs unterscheiden. Diese Anleitung führt Sie durch alles, was Sie benötigen, um eine vollständige Reddit-DM-Integration zu implementieren.
Reddits Messaging-System verarbeitet sowohl private Nachrichten zwischen Benutzern als auch Kommentarantworten in einer einheitlichen Inbox. Ihre Anwendung muss zwischen diesen Typen unterscheiden, Konversations-Threads verwalten und Reddits Rate-Limits angemessen handhaben.
Einführung in die Reddit API
Reddit bietet eine umfassende API für den Zugriff auf Benutzerdaten, das Posten von Inhalten und die Verwaltung privater Nachrichten. Die API verwendet OAuth 2.0 zur Authentifizierung und erfordert spezifische Scopes für verschiedene Operationen.
Für die Messaging-Funktionalität arbeiten Sie mit diesen primären Endpoints:
| Endpoint | Zweck | Methode |
|---|---|---|
/message/inbox | Alle Inbox-Elemente (Nachrichten + Kommentarantworten) | GET |
/message/messages | Nur private Nachrichten | GET |
/message/sent | Gesendete Nachrichten | GET |
/api/compose | Neue Nachricht senden | POST |
/api/comment | Auf Nachricht antworten | POST |
/api/read_message | Als gelesen markieren | POST |
Die reddit inbox api gibt Nachrichten in einem Listing-Format mit Paginierungsunterstützung zurück. Jede Nachricht enthält Metadaten über den Absender, Empfänger, Betreff und Konversations-Thread.

OAuth 2.0-Authentifizierung für Reddit
Bevor Sie auf die reddit private messages api zugreifen können, müssen Sie Benutzer mit den korrekten OAuth-Scopes authentifizieren. Der privatemessages-Scope gewährt Zugriff zum Lesen und Senden von Direktnachrichten.
interface RedditAuthConfig {
clientId: string;
clientSecret: string;
redirectUri: string;
scopes: string[];
}
const config: RedditAuthConfig = {
clientId: process.env.REDDIT_CLIENT_ID || '',
clientSecret: process.env.REDDIT_CLIENT_SECRET || '',
redirectUri: process.env.REDDIT_REDIRECT_URI || '',
scopes: ['identity', 'privatemessages', 'read', 'history']
};
function getAuthUrl(state: string): string {
const params = new URLSearchParams({
client_id: config.clientId,
response_type: 'code',
state: state,
redirect_uri: config.redirectUri,
duration: 'permanent',
scope: config.scopes.join(' '),
});
return `https://www.reddit.com/api/v1/authorize?${params.toString()}`;
}
async function exchangeCodeForToken(code: string): Promise {
const credentials = Buffer.from(
`${config.clientId}:${config.clientSecret}`
).toString('base64');
const response = await fetch('https://www.reddit.com/api/v1/access_token', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'YourApp/1.0.0',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: config.redirectUri,
}).toString(),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Token exchange failed: ${response.status} ${error}`);
}
return response.json();
}
interface TokenResponse {
access_token: string;
refresh_token: string;
expires_in: number;
scope: string;
token_type: string;
}
Hinweis: Reddit erfordert einen beschreibenden User-Agent-Header für alle API-Anfragen. Die Verwendung eines generischen oder fehlenden User-Agent führt zu Rate-Limiting oder blockierten Anfragen.
Verständnis von Fullnames (t1_, t3_, t4_)
Reddit verwendet ein "Fullname"-System zur Identifizierung aller Objekte in der API. Das Verständnis dieser Präfixe ist entscheidend bei der Arbeit mit der reddit dm api:
| Präfix | Objekttyp | Beispiel |
|---|---|---|
t1_ | Kommentar | t1_abc123 |
t2_ | Account | t2_xyz789 |
t3_ | Link/Post | t3_def456 |
t4_ | Nachricht | t4_ghi012 |
t5_ | Subreddit | t5_jkl345 |
Beim Antworten auf Nachrichten oder beim Markieren als gelesen müssen Sie den vollständigen Fullname einschließlich des Präfixes verwenden:
function normalizeFullname(id: string, type: 't1' | 't3' | 't4'): string {
if (id.startsWith(`${type}_`)) {
return id;
}
return `${type}_${id}`;
}
// Verwendungsbeispiele
const messageFullname = normalizeFullname('abc123', 't4'); // Gibt zurück: t4_abc123
const commentFullname = normalizeFullname('t1_xyz789', 't1'); // Gibt zurück: t1_xyz789
Abrufen von Inbox-Nachrichten
Der Inbox-Endpoint gibt alle Elemente zurück, einschließlich privater Nachrichten und Kommentarantworten. Um nur private Nachrichten abzurufen, verwenden Sie stattdessen den /message/messages-Endpoint.
interface RedditMessage {
id: string;
name: string; // Fullname (t4_xxx)
author: string;
dest: string;
subject: string;
body: string;
created_utc: number;
new: boolean;
was_comment: boolean;
first_message_name: string | null;
}
interface InboxResponse {
messages: RedditMessage[];
after: string | null;
}
async function fetchInboxMessages(
accessToken: string,
options: { limit?: number; after?: string } = {}
): Promise {
const limit = Math.min(options.limit || 25, 100);
let url = `https://oauth.reddit.com/message/messages?limit=${limit}&raw_json=1`;
if (options.after) {
url += `&after=${options.after}`;
}
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': 'YourApp/1.0.0',
},
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to fetch inbox: ${response.status} ${error}`);
}
const data = await response.json();
const messages: RedditMessage[] = (data.data?.children || [])
.filter((item: any) => !item.data.was_comment) // Kommentarantworten herausfiltern
.map((item: any) => ({
id: item.data.id,
name: item.data.name,
author: item.data.author,
dest: item.data.dest,
subject: item.data.subject,
body: item.data.body,
created_utc: item.data.created_utc,
new: item.data.new,
was_comment: item.data.was_comment,
first_message_name: item.data.first_message_name,
}));
return {
messages,
after: data.data?.after || null,
};
}
Das first_message_name-Feld ist wichtig für das Threading. Nachrichten in derselben Konversation teilen diesen Wert, sodass Sie sie zusammengruppieren können.
Senden von privaten Nachrichten mit der Reddit API
Um eine neue private Nachricht zu senden, verwenden Sie den /api/compose-Endpoint. Dieser Endpoint erfordert den Benutzernamen des Empfängers, eine Betreffzeile und den Nachrichtentext.
interface SendMessageParams {
to: string;
subject: string;
text: string;
}
interface SendMessageResult {
success: boolean;
errors?: string[];
}
async function sendPrivateMessage(
accessToken: string,
params: SendMessageParams
): Promise {
const { to, subject, text } = params;
// Eingaben validieren
if (!to || !subject || !text) {
return {
success: false,
errors: ['Empfänger, Betreff und Nachrichtentext sind erforderlich'],
};
}
if (subject.length > 100) {
return {
success: false,
errors: ['Betreff muss 100 Zeichen oder weniger sein'],
};
}
const response = await fetch('https://oauth.reddit.com/api/compose', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': 'YourApp/1.0.0',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
api_type: 'json',
to,
subject,
text,
}).toString(),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to send message: ${response.status} ${error}`);
}
const data = await response.json();
const errors = data.json?.errors || [];
if (errors.length > 0) {
return {
success: false,
errors: errors.map((e: any[]) => e.join(': ')),
};
}
return { success: true };
}
Hinweis: Reddit beschränkt neue Accounts beim Senden privater Nachrichten. Benutzer müssen möglicherweise ihre E-Mail verifizieren und ein gewisses Kontoalter haben, bevor die Messaging-Funktion verfügbar wird.
Antworten auf Nachrichten
Das Antworten auf eine bestehende Nachricht verwendet den /api/comment-Endpoint (derselbe Endpoint, der für Kommentarantworten verwendet wird). Sie benötigen den Fullname der Nachricht, auf die Sie antworten.
interface ReplyResult {
success: boolean;
replyId?: string;
errors?: string[];
}
async function replyToMessage(
accessToken: string,
messageFullname: string,
text: string
): Promise {
// Korrektes Fullname-Format sicherstellen
const fullname = messageFullname.startsWith('t4_')
? messageFullname
: `t4_${messageFullname}`;
const response = await fetch('https://oauth.reddit.com/api/comment', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': 'YourApp/1.0.0',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
api_type: 'json',
thing_id: fullname,
text,
}).toString(),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to reply: ${response.status} ${error}`);
}
const data = await response.json();
const errors = data.json?.errors || [];
if (errors.length > 0) {
return {
success: false,
errors: errors.map((e: any[]) => e.join(': ')),
};
}
const replyData = data.json?.data?.things?.[0]?.data;
return {
success: true,
replyId: replyData?.id,
};
}
Nachrichten-Threading und Gruppierung
Reddit gruppiert Nachrichten in Konversationen mithilfe des first_message_name-Feldes. Der Aufbau einer Konversationsansicht erfordert das Abrufen von Nachrichten aus sowohl Inbox- als auch Gesendet-Ordnern und deren anschließende Gruppierung nach Thread.
interface Conversation {
id: string;
participantUsername: string;
subject: string;
messages: ThreadMessage[];
lastUpdated: Date;
hasUnread: boolean;
}
interface ThreadMessage {
id: string;
fullname: string;
text: string;
sentAt: Date;
isFromMe: boolean;
senderUsername: string;
}
async function getConversations(
accessToken: string,
myUsername: string
): Promise {
// Sowohl Inbox- als auch gesendete Nachrichten abrufen
const [inboxResponse, sentResponse] = await Promise.all([
fetch('https://oauth.reddit.com/message/messages?limit=100&raw_json=1', {
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': 'YourApp/1.0.0',
},
}),
fetch('https://oauth.reddit.com/message/sent?limit=100&raw_json=1', {
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': 'YourApp/1.0.0',
},
}),
]);
const inboxData = await inboxResponse.json();
const sentData = await sentResponse.json();
const allMessages: any[] = [
...(inboxData.data?.children || []),
...(sentData.data?.children || []),
];
// Nach Konversation gruppieren
const conversationsMap = new Map();
const seenMessageIds = new Set();
for (const item of allMessages) {
const msg = item.data;
// Duplikate und Kommentarantworten überspringen
if (seenMessageIds.has(msg.name) || msg.was_comment) {
continue;
}
seenMessageIds.add(msg.name);
const conversationId = msg.first_message_name || msg.name;
const isFromMe = msg.author?.toLowerCase() === myUsername.toLowerCase();
const otherParticipant = isFromMe ? msg.dest : msg.author;
const threadMessage: ThreadMessage = {
id: msg.id,
fullname: msg.name,
text: msg.body,
sentAt: new Date(msg.created_utc * 1000),
isFromMe,
senderUsername: msg.author,
};
if (!conversationsMap.has(conversationId)) {
conversationsMap.set(conversationId, {
id: conversationId,
participantUsername: otherParticipant,
subject: msg.subject,
messages: [threadMessage],
lastUpdated: threadMessage.sentAt,
hasUnread: msg.new && !isFromMe,
});
} else {
const conversation = conversationsMap.get(conversationId)!;
conversation.messages.push(threadMessage);
if (threadMessage.sentAt > conversation.lastUpdated) {
conversation.lastUpdated = threadMessage.sentAt;
}
if (msg.new && !isFromMe) {
conversation.hasUnread = true;
}
}
}
// Nachrichten innerhalb jeder Konversation sortieren und Konversationen nach letzter Aktualisierung sortieren
const conversations = Array.from(conversationsMap.values());
for (const conv of conversations) {
conv.messages.sort((a, b) => a.sentAt.getTime() - b.sentAt.getTime());
}
conversations.sort((a, b) => b.lastUpdated.getTime() - a.lastUpdated.getTime());
return conversations;
}
Nachrichten als gelesen markieren
Der /api/read_message-Endpoint akzeptiert eine kommagetrennte Liste von Fullnames, sodass Sie mehrere Nachrichten in einer einzigen Anfrage als gelesen markieren können.
async function markMessagesAsRead(
acc