Costruire un'integrazione Reddit che gestisca i messaggi privati richiede la comprensione dell'approccio unico di Reddit alla messaggistica. Il sistema reddit api messages utilizza una combinazione di endpoint inbox, identificatori fullname e scope OAuth che differiscono dalle tipiche API di messaggistica. Questa guida ti accompagna attraverso tutto ciò che devi implementare per un'integrazione completa dei DM Reddit.
Il sistema di messaggistica di Reddit gestisce sia i messaggi privati tra utenti che le risposte ai commenti in un inbox unificato. La tua applicazione deve distinguere tra questi tipi, gestire i thread delle conversazioni e gestire appropriatamente i rate limit di Reddit.
Introduzione all'API Reddit
Reddit fornisce un'API completa per accedere ai dati degli utenti, pubblicare contenuti e gestire i messaggi privati. L'API utilizza OAuth 2.0 per l'autenticazione e richiede scope specifici per diverse operazioni.
Per le funzionalità di messaggistica, lavorerai con questi endpoint principali:
| Endpoint | Scopo | Metodo |
|---|---|---|
/message/inbox | Tutti gli elementi inbox (messaggi + risposte ai commenti) | GET |
/message/messages | Solo messaggi privati | GET |
/message/sent | Messaggi inviati | GET |
/api/compose | Invia nuovo messaggio | POST |
/api/comment | Rispondi al messaggio | POST |
/api/read_message | Segna come letto | POST |
La reddit inbox api restituisce i messaggi in un formato listing con supporto alla paginazione. Ogni messaggio include metadati sul mittente, destinatario, oggetto e thread della conversazione.

Autenticazione OAuth 2.0 per Reddit
Prima di accedere alla reddit private messages api, devi autenticare gli utenti con gli scope OAuth corretti. Lo scope privatemessages garantisce l'accesso per leggere e inviare messaggi diretti.
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<TokenResponse> {
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;
}
Nota: Reddit richiede un header User-Agent descrittivo per tutte le richieste API. Usare un User-Agent generico o mancante risulterà in rate limiting o richieste bloccate.
Comprendere i Fullname (t1_, t3_, t4_)
Reddit utilizza un sistema "fullname" per identificare tutti gli oggetti nell'API. Comprendere questi prefissi è fondamentale quando si lavora con la reddit dm api:
| Prefisso | Tipo di Oggetto | Esempio |
|---|---|---|
t1_ | Commento | t1_abc123 |
t2_ | Account | t2_xyz789 |
t3_ | Link/Post | t3_def456 |
t4_ | Messaggio | t4_ghi012 |
t5_ | Subreddit | t5_jkl345 |
Quando rispondi ai messaggi o li segni come letti, devi usare il fullname completo incluso il prefisso:
function normalizeFullname(id: string, type: 't1' | 't3' | 't4'): string {
if (id.startsWith(`${type}_`)) {
return id;
}
return `${type}_${id}`;
}
// Esempi di utilizzo
const messageFullname = normalizeFullname('abc123', 't4'); // Restituisce: t4_abc123
const commentFullname = normalizeFullname('t1_xyz789', 't1'); // Restituisce: t1_xyz789
Recuperare i Messaggi dell'Inbox
L'endpoint inbox restituisce tutti gli elementi inclusi i messaggi privati e le risposte ai commenti. Per recuperare solo i messaggi privati, usa invece l'endpoint /message/messages.
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<InboxResponse> {
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) // Filtra le risposte ai commenti
.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,
};
}
Il campo first_message_name è importante per il threading. I messaggi nella stessa conversazione condividono questo valore, permettendoti di raggrupparli insieme.
Inviare Messaggi Privati con l'API Reddit
Per inviare un nuovo messaggio privato, usa l'endpoint /api/compose. Questo endpoint richiede il nome utente del destinatario, un oggetto e il corpo del messaggio.
interface SendMessageParams {
to: string;
subject: string;
text: string;
}
interface SendMessageResult {
success: boolean;
errors?: string[];
}
async function sendPrivateMessage(
accessToken: string,
params: SendMessageParams
): Promise<SendMessageResult> {
const { to, subject, text } = params;
// Valida gli input
if (!to || !subject || !text) {
return {
success: false,
errors: ['Destinatario, oggetto e testo del messaggio sono obbligatori'],
};
}
if (subject.length > 100) {
return {
success: false,
errors: ['L\'oggetto deve essere di 100 caratteri o meno'],
};
}
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 };
}
Nota: Reddit limita i nuovi account dall'invio di messaggi privati. Gli utenti potrebbero dover verificare la loro email e avere una certa anzianità dell'account prima che la funzionalità di messaggistica diventi disponibile.
Rispondere ai Messaggi
Rispondere a un messaggio esistente usa l'endpoint /api/comment (lo stesso endpoint usato per le risposte ai commenti). Hai bisogno del fullname del messaggio a cui stai rispondendo.
interface ReplyResult {
success: boolean;
replyId?: string;
errors?: string[];
}
async function replyToMessage(
accessToken: string,
messageFullname: string,
text: string
): Promise<ReplyResult> {
// Assicura il formato fullname corretto
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,
};
}
Threading e Raggruppamento dei Messaggi
Reddit raggruppa i messaggi in conversazioni usando il campo first_message_name. Costruire una vista conversazione richiede il recupero dei messaggi sia dalla cartella inbox che da quella dei messaggi inviati, per poi raggrupparli per 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<Conversation[]> {
// Recupera sia i messaggi inbox che quelli inviati
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 || []),
];
// Raggruppa per conversazione
const conversationsMap = new Map<string, Conversation>();
const seenMessageIds = new Set<string>();
for (const item of allMessages) {
const msg = item.data;
// Salta i duplicati e le risposte ai commenti
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;
}
}
}
// Ordina i messaggi all'interno di ogni conversazione e ordina le conversazioni per ultimo aggiornamento
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;
}
Segnare i Messaggi come Letti
L'endpoint /api/read_message accetta una lista di fullname separati da virgola, permettendoti di segnare più messaggi come letti in una singola richiesta.
async function markMessagesAsRead(
acc