Direct
| Method | Return | Description |
|---|---|---|
direct_threads(amount: int = 20, selected_filter: Optional[Literal["flagged", "unread"]] = None, box: Optional[Literal["primary", "general"]] = None, thread_message_limit: Optional[int] = None) Note: omit selected_filter / box or pass None for the default inbox |
List[DirectThread] | Get all threads from inbox |
| direct_pending_inbox(amount: int = 20) | List[DirectThread] | Get all threads from pending inbox |
| direct_requests(amount: int = 20) | List[DirectThread] | Get message request threads (pending inbox / invitations) |
| direct_pending_requests_preview(pending_inbox_filters: Optional[List[str]] = None) | Dict | Get lightweight pending request counters |
| direct_request_approve(thread_id: int) | bool | Approve a message request thread |
| direct_has_interop_upgraded() | bool | Check Direct interop upgrade state |
| direct_search_gen_ai_bots(amount: int = 20) | List[UserShort] | Search generated AI bot suggestions |
| direct_channels(user_id: Optional[int] = None, thread_subtypes: Optional[List[int]] = None) | List[Dict] | Get Direct channels for a user |
| direct_set_e2ee_eligibility(e2ee_eligibility: int = 4) | bool | Set Direct E2EE eligibility state |
| direct_thread(thread_id: int, amount: int = 20) | DirectThread | Get Thread with Messages |
| direct_messages(thread_id: int, amount: int = 20) | List[DirectMessage] | Get only Messages in Thread |
| direct_message(thread_id: int, message_id: int, amount: int = 20) | DirectMessage | Get one Message from Thread by id |
| direct_answer(thread_id: int, text: str) | DirectMessage | Add Message to exist Thread |
| direct_send(text: str, user_ids: List[int] = [], thread_ids: List[int] = [], send_attribute: SEND_ATTRIBUTE = "message_button", reply_to_message: Optional[DirectMessage] = None, *, nav_chain: Optional[str] = None) | DirectMessage | Send a text or link message, optionally as a reply, with request-specific navigation metadata |
| direct_send_reaction(thread_id: int, message_id: int, emoji: str = "❤", client_context: Optional[str] = None) | bool | Send an emoji reaction to a message |
| direct_delete_reaction(thread_id: int, message_id: int, emoji: str = "❤", client_context: Optional[str] = None) | bool | Delete your emoji reaction from a message |
| direct_message_like(thread_id: int, message_id: int, client_context: Optional[str] = None) | bool | Like a message with a heart reaction |
| direct_message_unlike(thread_id: int, message_id: int, client_context: Optional[str] = None) | bool | Remove your heart reaction from a message |
| direct_search(query: str) | List[DirectShortThread] | Search threads (for example by username) |
| direct_thread_by_participants(user_ids: List[int]) | DirectThread | Get thread by user_id |
| direct_thread_create(user_ids: List[int], title: str = "") | str | Create a group thread and return its thread id |
| direct_thread_add_users(thread_id: int, user_ids: List[int]) | bool | Add users to a group thread |
| direct_thread_hide(thread_id: int) | bool | Delete (called "hide") |
| direct_thread_update_title(thread_id: int, title: str) | bool | Update a group thread title |
| direct_media_share(media_id: str, user_ids: List[int] = [], thread_ids: List[int] = [], send_attribute: SEND_ATTRIBUTE_MEDIA = "feed_timeline", media_type: DirectMediaType = "photo") | DirectMessage | Share a media to users or existing threads |
| direct_story_share(story_id: str, user_ids: List[int], thread_ids: List[int]) | DirectMessage | Share a story to list of users |
| direct_profile_share(user_id: str, user_ids: List[int], thread_ids: List[int]) | DirectMessage | Share a user profile to list of users |
| direct_thread_mark_unread(thread_id: int) | bool | Mark a thread as unread |
| direct_message_delete(thread_id: int, message_id: int) | bool | Delete a message from thread |
| direct_message_unsend(thread_id: int, message_id: int) | bool | Unsend a message from thread |
| direct_thread_mute(thread_id: int, revert: bool = False) | bool | Mute the thread |
| direct_thread_unmute(thread_id: int) | bool | Unmute the thread |
| direct_thread_mute_video_call(thread_id: int, revert: bool = False) | bool | Mute video call for the thread |
| direct_thread_unmute_video_call(thread_id: int) | bool | Unmute video call for the thread |
| direct_send_photo(path: Path, user_ids: List[int], thread_ids: List[int]) | DirectMessage | Send a direct photo to users in an existing thread or directly to thread ids |
| direct_send_video(path: Path, user_ids: List[int], thread_ids: List[int]) | DirectMessage | Send a direct video (.mp4 / H.264 + AAC) to list of users or threads |
| direct_send_voice(path: Path, user_ids: List[int], thread_ids: List[int], waveform: Optional[List[float]]) | DirectMessage | Send a direct voice (audio) message; path must be m4a/AAC |
| video_upload_to_direct(path: Path, caption: str, thumbnail: Path, mentions: List[StoryMention], thread_ids: List[int] = [], extra_data: Dict[str, str] = {}) | DirectMessage | Upload video to direct thread as a story and configure it |
Navigation metadata for text and link messages
direct_send() uses the same navigation chain in the X-IG-Nav-Chain header and the request body. Its keyword-only nav_chain argument applies to that send, including link messages and replies, and does not change session headers or later requests. Omitting it (or passing None) preserves the existing Direct body chain as the default; the SDK does not track application screen transitions.
Use send_attribute="message_button" (the default), "inbox_search", or "inbox". The Python argument is named send_attribute; the wire field is send_attribution. When providing a custom chain, choose the attribution that matches your entry path. The chain is preserved verbatim and must be a nonempty printable ASCII string without leading or trailing whitespace. Invalid values raise ValueError before sending.
# navigation_chain is the current chain supplied by your application.
cl.direct_send(
"Hello",
thread_ids=[thread.id],
send_attribute="inbox",
nav_chain=navigation_chain,
)
These options cover direct_send() text/link requests. They do not establish that navigation metadata causes or resolves Direct restrictions or error 1404006.
Option types
Direct media type is exposed as DirectMediaType = Literal["photo", "video"].
| Type | Values | Used by |
|---|---|---|
DirectMediaType |
"photo", "video" |
direct_send_file(content_type=...), direct_media_share(media_type=...) |
Notes:
- For
direct_send(),direct_media_share(),direct_send_photo(),direct_send_video(), anddirect_send_voice(), pass exactly one ofuser_idsorthread_ids. - Direct recipient arguments accept either one id (
user_ids=123) or a list of ids (user_ids=[123]). - Direct photo, video, and voice attachments sent with
user_idsrequire an existing Direct thread. Usedirect_send()to start the conversation first, or preferthread_idswhen the thread id is already known. - Direct message requests / invitations are exposed as
direct_requests();direct_pending_inbox()remains as the older name. direct_pending_requests_preview()is the lightweight Android-app preview for request counters; usedirect_requests()when you need the actual threads.direct_channels()anddirect_search_gen_ai_bots()expose raw app surfaces whose response shape may vary by rollout.direct_thread()paginates internally until it collectsamountmessages or reaches the end of the thread.direct_message()scans the latestamountmessages in a thread and raisesDirectMessageNotFoundif the id is not present in that window.- Shared XMA items such as
xma_clip,xma_media_share,xma_story_share, andxma_profilekeep their original payload inmessage.raw_xma. When Instagram includestarget_url, the normalized link is also available throughmessage.xma_share. - Disappearing direct photos and videos, including incoming Direct quicksnaps with
item_type == "raven_media", are exposed throughmessage.visual_media. - Media-changing direct endpoints are more sensitive to session quality than read-only inbox calls. Stable sessions loaded via
dump_settings()/load_settings()are more reliable than browser-onlysessionidreuse.
Incoming quicksnaps
Instagram returns snaps sent to you through Direct threads, not through quicksnap_history().
Fetch the inbox or a known thread and filter Direct messages whose item_type is
"raven_media" and whose visual_media field is present.
threads = cl.direct_threads(amount=20, thread_message_limit=20)
for thread in threads:
for message in thread.messages:
if message.item_type == "raven_media" and message.visual_media:
media = message.visual_media.media
image_versions = media.image_versions2
video_versions = media.video_versions or []
image_url = image_versions.candidates[-1].url if image_versions else None
video_url = video_versions[-1].url if video_versions else None
print(thread.id, message.id, media.media_type, image_url or video_url)
For one known thread:
messages = cl.direct_messages(thread_id, amount=50)
incoming_snaps = [message for message in messages if message.item_type == "raven_media" and message.visual_media]
Instagram may omit playable media URLs after a disappearing photo or video has
expired or already been viewed. In that case the message can still appear in the
thread as a placeholder or action summary. quicksnap_history() returns the
authenticated user's QuickSnap history payload and is not the Direct inbox for
snaps sent by other users.
Handling disabled message requests:
from instagrapi.exceptions import DirectMessageRequestsDisabled
try:
cl.direct_send("Hello", user_ids=[user_id])
except DirectMessageRequestsDisabled:
print("The recipient does not accept new Direct message requests.")
Example of basic actions:
>>> from instagrapi import Client
>>> cl = Client()
>>> cl.login(USERNAME, PASSWORD)
>>> thread = cl.direct_threads(1)[0]
>>> thread.pk
18123276039123479
>>> thread.users
[UserShort(pk=123123123, username='something', full_name='Dima Something', profile_pic_url=HttpUrl('https://instagram.frix7-1.fna.fbcdn.net/v/t51.2885-19/s150x150/11374323_1630877790512376_1081658215_a.jpg?_nc_ht=instagram.frix7-1.fna.fbcdn.net&_nc_ohc=k22oMvVv8xEAX-UEVRB&edm=AI8ESKwBAAAA&ccb=7-4&oh=be799948b28f19d85158153d886d16d3&oe=6135D80F&_nc_sid=195af5', scheme='https', host='instagram.frix7-1.fna.fbcdn.net', tld='net', host_type='domain', path='/v/t51.2885-19/s150x150/11374323_1630877790512376_1081658215_a.jpg', query='_nc_ht=instagram.frix7-1.fna.fbcdn.net&_nc_ohc=k22oMvVv8xEAX-UEVRB&edm=AI8ESKwBAAAA&ccb=7-4&oh=be799948b28f19d85158153d886d16d3&oe=6135D80F&_nc_sid=195af5'), profile_pic_url_hd=None, is_private=False, stories=[])]
>>> thread.messages[0]
DirectMessage(id=300761992574947211231231241955932160, user_id=123123123, thread_id=None, timestamp=datetime.datetime(2021, 8, 31, 18, 20, 28, 754135, tzinfo=datetime.timezone.utc), item_type='text', is_shh_mode=False, reactions=None, text='Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_pending_inbox(1)[0]
DirectThread(
pk=17881231232408606,
id=3402823668123123123949128156938656669726,
messages=[
DirectMessage(
id=30073094913010429825449992959033344,
user_id=123123123123,
...
)
],
...
)
>>> request = cl.direct_requests(1)[0]
>>> cl.direct_request_approve(request.id)
True
>>> cl.direct_thread(thread.id, 1)
DirectThread(
pk=18103276039108479,
id=340282366841710300949128373114263369599,
messages=[
DirectMessage(
id=30076199257494728485375741955932160,
user_id=7789547,
...
)
],
...
)
>>> message = cl.direct_messages(thread.id, 1)[0]
DirectMessage(id=300712312341231237412312312360, user_id=12312312, thread_id=None, timestamp=datetime.datetime(2021, 8, 31, 18, 20, 28, 754135, tzinfo=datetime.timezone.utc), item_type='text', is_shh_mode=False, reactions=None, text='Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_message(thread.id, message.id)
DirectMessage(id=300712312341231237412312312360, user_id=12312312, thread_id=None, timestamp=datetime.datetime(2021, 8, 31, 18, 20, 28, 754135, tzinfo=datetime.timezone.utc), item_type='text', is_shh_mode=False, reactions=None, text='Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_answer(thread.id, 'Hello!')
DirectMessage(id=30076213210116812312341061613568, user_id=None, thread_id=34028236684171031231231231233331238762, timestamp=datetime.datetime(2021, 8, 31, 18, 33, 5, 127298, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_send('How are you?', user_ids=[cl.user_id]) # send youself
DirectMessage(id=30076213210116812312341061613568, user_id=None, thread_id=34028236684171031231231231233331238762, timestamp=datetime.datetime(2021, 8, 31, 18, 33, 5, 127298, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_send('How are you?', thread_ids=[thread.id])
DirectMessage(id=30076213210116812312341061613568, user_id=None, thread_id=34028236684171031231231231233331238762, timestamp=datetime.datetime(2021, 8, 31, 18, 33, 5, 127298, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_send('Reply text', thread_ids=[thread.id], reply_to_message=message)
DirectMessage(id=30076213210116812312341061613568, user_id=None, thread_id=34028236684171031231231231233331238762, timestamp=datetime.datetime(2021, 8, 31, 18, 33, 5, 127298, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_send_reaction(thread.id, message.id, emoji="😂", client_context=message.client_context)
True
>>> cl.direct_message_like(thread.id, message.id, client_context=message.client_context)
True
>>> cl.direct_message_unlike(thread.id, message.id, client_context=message.client_context)
True
>>> cl.direct_thread_by_participants([cl.user_id])
DirectThread(pk=178612312342, id=340282366812312312312341298762, messages=[DirectMessage(id=30076214123123123123123864, user_id=1903424587, thread_id=None, timestamp=datetime.datetime(2021, 8, 31, 18, 33, 49, 107154, ...)
>>> thread_id = cl.direct_thread_create([user_id_1, user_id_2], title="New group")
>>> cl.direct_thread(thread_id, amount=1)
DirectThread(pk=178612312342, id=340282366812312312312341298762, messages=[...], ...)
>>> cl.direct_thread_add_users(thread_id, [user_id_3])
True
>>> cl.direct_thread_update_title(thread.id, "New group title")
True
>>> cl.direct_media_share(media.pk, user_ids=[cl.user_id])
DirectMessage(id=3007629312312312312312300374016, user_id=None, thread_id=340282366812313212334410641298762, timestamp=datetime.datetime(2021, 8, 31, 19, 45, 20, 708276, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_media_share(media.pk, thread_ids=[thread.id])
DirectMessage(id=3007629312312312312312300374016, user_id=None, thread_id=340282366812313212334410641298762, timestamp=datetime.datetime(2021, 8, 31, 19, 45, 20, 708276, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_story_share(media.pk, user_ids=[cl.user_id])
DirectMessage(id=30076291231321231369939116032, user_id=None, thread_id=340282312312312334410641298762, timestamp=datetime.datetime(2021, 8, 31, 19, 48, 12, 217677, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_story_share(media.pk, thread_ids=[thread.id])
DirectMessage(id=30076291231231230352896, user_id=None, thread_id=3402812312312310641298762, timestamp=datetime.datetime(2021, 8, 31, 19, 48, 38, 482706, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_message_delete(thread.id, message.pk)
True
>>> cl.direct_message_unsend(thread.id, message.id)
True
>>> photo_path = cl.photo_download(cl.media_pk_from_url('https://www.instagram.com/p/BgqFyjqloOr/'))
>>> cl.direct_send_photo(photo_path, user_ids=[cl.user_id]) # or
>>> cl.direct_send_photo(photo_path, thread_ids=[thread.id])
DirectMessage(id=300775273512312312312321568, user_id=None, thread_id=34028236123123123123128762, timestamp=datetime.datetime(2021, 9, 1, 14, 20, 24, 949673, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> video_path = cl.video_download(cl.media_pk_from_url('https://www.instagram.com/p/B3rFQPblq40/'))
>>> cl.direct_send_video(video_path, user_ids=[cl.user_id]) # or
>>> cl.direct_send_video(video_path, thread_ids=[thread.id])
>>> # Voice/audio DM. Audio MUST be AAC in an MP4 container (.m4a).
>>> # Convert via ffmpeg first if needed:
>>> # ffmpeg -i input.wav -c:a aac -b:a 64k -ac 1 -ar 44100 voice.m4a
>>> cl.direct_send_voice("voice.m4a", thread_ids=[thread.id])
Analyzing video file "/.../example_2155839952940084788.mp4"
DirectMessage(id=300775489123123123123664, user_id=None, thread_id=34012312312312312398762, timestamp=datetime.datetime(2021, 9, 1, 14, 39, 56, 959454, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.video_upload_to_direct(video_path, thread_ids=[thread.id])
Analyzing video file "/.../example_2155839952940084788.mp4"
Generating thumbnail "/.../example_2155839952940084788.mp4.jpg"...
DirectMessage(id=3007123123123123664, user_id=None, thread_id=3401212312312312398762, timestamp=datetime.datetime(2021, 9, 1, 14, 39, 56, 959454, tzinfo=datetime.timezone.utc), item_type=None, is_shh_mode=None, reactions=None, text=None, animated_media=None, media=None, media_share=None, reel_share=None, story_share=None, felix_share=None, clip=None, placeholder=None)
>>> cl.direct_thread_mark_unread(340282366841710301949128122292511813703)
True
>>> cl.direct_thread_mute(340282366841710301949128122292511813703)
True
>>> cl.direct_thread_mute_video_call(340282366841710301949128122292511813703)
True
>>> cl.direct_thread_unmute_video_call(340282366841710301949128122292511813703)
True
>>> cl.direct_thread_unmute(340282366841710301949128122292511813703)
True