This guide covers the key concepts you need to integrate the Direct Messages lookup endpoints into your application.
Authentication
DM endpoints require user authentication to access private conversations:
App-Only authentication is not supported. All Direct Messages are private.
Required scopes (OAuth 2.0)
Scope Required for dm.readReading DM events tweet.readRequired with dm.read users.readRequired with dm.read
Conversation types
One-to-one Always has exactly two participants. Conversation ID format: {smaller_user_id}-{larger_user_id}
Group Two or more participants. Membership can change over time.
Event types
Event Description Key fields MessageCreateA message was sent text, sender_idParticipantsJoinUser joined group participant_ids, sender_idParticipantsLeaveUser left group participant_ids
Example events
{
"id" : "1582838499983564806" ,
"event_type" : "MessageCreate" ,
"text" : "Hi everyone." ,
"sender_id" : "944480690" ,
"dm_conversation_id" : "1578398451921985538" ,
"created_at" : "2022-10-19T20:58:00.000Z"
}
{
"id" : "1582835469712138240" ,
"event_type" : "ParticipantsJoin" ,
"participant_ids" : [ "944480690" ],
"sender_id" : "17200003" ,
"dm_conversation_id" : "1578398451921985538" ,
"created_at" : "2022-10-19T20:45:58.000Z"
}
{
"id" : "1582838535115067392" ,
"event_type" : "ParticipantsLeave" ,
"participant_ids" : [ "944480690" ],
"dm_conversation_id" : "1578398451921985538" ,
"created_at" : "2022-10-19T20:58:09.000Z"
}
Fields and expansions
Default fields
Event type Default fields MessageCreate id, event_type, textParticipantsJoin/Leave id, event_type, participant_ids
Available fields
Field Description Events dm_conversation_idConversation ID All created_atEvent timestamp All sender_idWho sent/invited MessageCreate, Join attachmentsMedia attachments MessageCreate referenced_tweetsShared Posts MessageCreate
Available expansions
Expansion Returns sender_idUser object for sender participant_idsUser objects for participants attachments.media_keysMedia objects referenced_tweets.idPost objects
Example with expansions
curl "https://api.x.com/2/dm_events? \
dm_event.fields=created_at,sender_id,attachments& \
expansions=sender_id,attachments.media_keys& \
user.fields=username,profile_image_url& \
media.fields=url,type" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN "
from xdk import Client
client = Client( bearer_token = "YOUR_USER_ACCESS_TOKEN" )
# Get DM events with expansions
for page in client.dm_events.list(
dm_event_fields = [ "created_at" , "sender_id" , "attachments" ],
expansions = [ "sender_id" , "attachments.media_keys" ],
user_fields = [ "username" , "profile_image_url" ],
media_fields = [ "url" , "type" ],
max_results = 100
):
for event in page.data:
print ( f "Event: { event.event_type } - { event.text } " )
import { Client } from "@xdevplatform/xdk" ;
const client = new Client ({ accessToken: "YOUR_USER_ACCESS_TOKEN" });
const paginator = client . dmEvents . list ({
dmEventFields: [ "created_at" , "sender_id" , "attachments" ],
expansions: [ "sender_id" , "attachments.media_keys" ],
userFields: [ "username" , "profile_image_url" ],
mediaFields: [ "url" , "type" ],
maxResults: 100 ,
});
for await ( const page of paginator ) {
page . data ?. forEach (( event ) => {
console . log ( `Event: ${ event . event_type } - ${ event . text } ` );
});
}
DM events are returned in reverse chronological order (newest first):
# First request
curl "https://api.x.com/2/dm_events?max_results=100" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN "
# Subsequent request with pagination token
curl "https://api.x.com/2/dm_events?max_results=100&pagination_token=NEXT_TOKEN" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN "
from xdk import Client
client = Client( bearer_token = "YOUR_USER_ACCESS_TOKEN" )
# The SDK handles pagination automatically
all_events = []
for page in client.dm_events.list( max_results = 100 ):
if page.data:
all_events.extend(page.data)
print ( f "Found { len (all_events) } DM events" )
import { Client } from "@xdevplatform/xdk" ;
const client = new Client ({ accessToken: "YOUR_USER_ACCESS_TOKEN" });
async function getAllDMEvents () {
const allEvents = [];
// The SDK handles pagination automatically
const paginator = client . dmEvents . list ({ maxResults: 100 });
for await ( const page of paginator ) {
if ( page . data ) {
allEvents . push ( ... page . data );
}
}
return allEvents ;
}
// Usage
const events = await getAllDMEvents ();
console . log ( `Found ${ events . length } DM events` );
Events from up to 30 days ago are available.
ID compatibility with v1.1
Conversation and event IDs are shared between v1.1 and v2 endpoints. This means you can:
Use v2 to retrieve events, then use v1.1 to delete specific messages
Reference conversation IDs from x.com URLs in API requests
Next steps
Quickstart Make your first DM lookup request
Send DMs Send Direct Messages
API Reference Full endpoint documentation
Sample code Working code examples