Skip to main content
This guide covers the key concepts you need to integrate the manage Direct Messages endpoints into your application.

Authentication

DM endpoints require user authentication:
MethodDescription
OAuth 2.0 Authorization Code with PKCERecommended
OAuth 1.0a User ContextLegacy support
App-Only authentication is not supported. All Direct Messages are private.

Required scopes (OAuth 2.0)

ScopeRequired for
dm.writeSending and deleting messages
dm.readRequired with dm.write
tweet.readRequired with dm scopes
users.readRequired with dm scopes

Endpoints overview

MethodEndpointDescription
POST/2/dm_conversations/with/:participant_id/messagesSend one-to-one message
POST/2/dm_conversationsCreate group conversation
POST/2/dm_conversations/:dm_conversation_id/messagesAdd message to conversation
DELETE/2/dm_events/:event_idDelete a message

Sending messages

One-to-one message

Send a message to a specific user. Creates a new conversation if one doesn’t exist:
cURL
curl -X POST "https://api.x.com/2/dm_conversations/with/9876543210/messages" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello!"}'

Group conversation

Create a new group and send the first message:
cURL
curl -X POST "https://api.x.com/2/dm_conversations" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_type": "Group",
    "participant_ids": ["944480690", "906948460078698496"],
    "message": {"text": "Welcome to our group!"}
  }'
The conversation_type field must be set to "Group" (case sensitive).

Add to existing conversation

Send a message to any conversation you’re part of:
cURL
curl -X POST "https://api.x.com/2/dm_conversations/1582103724607971328/messages" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text": "Another message"}'

Media attachments

Attach one piece of media (photo, video, or GIF) per message.
1

Upload media

Use the Media Upload endpoint to upload your file and get a media_id.
2

Include in message

{
  "text": "Check out this image!",
  "attachments": [{"media_id": "1583157113245011970"}]
}
  • The authenticated user must have uploaded the media
  • Media is available for 24 hours after upload
  • Only one attachment per message is supported

Sharing Posts

Include a Post in your message by adding the Post URL to the text:
{
  "text": "Have you seen this? https://x.com/XDevelopers/status/1580559079470145536"
}
The response will include a referenced_tweets field with the Post ID.

Message requirements

FieldRequiredNotes
textYes*Required if no attachments
attachmentsYes*Required if no text
*At least one of text or attachments must be provided.

ID compatibility with v1.1

Conversation and event IDs are shared between v1.1 and v2 endpoints. This enables hybrid workflows:
  • Create messages with v2
  • Delete messages with v1.1 (not yet available in v2)
  • Reference conversation IDs from x.com URLs

Error handling

StatusErrorSolution
400Invalid requestCheck request body format
401UnauthorizedVerify access token
403ForbiddenCheck scopes and user permissions
429Too Many RequestsWait and retry

Common issues

The recipient may have DM settings that prevent messages from unknown users, or may have blocked you.
Ensure the media was uploaded by the same authenticated user and is less than 24 hours old.
Verify all participant IDs are valid and the users allow group DM invites.

Next steps