Workflow to post media tweets and DM attachments
Use this workflow when Ruby code needs to post a media-backed tweet. That code can be a Ruby app, Rails job, Sidekiq worker, or agent service. Use it too when the code replies with media. It also covers sending one uploaded media item in a DM. Tweet and reply media posts use public media URLs directly onPOST /x/tweets. Send up to 4 image URLs or exactly 1 MP4 video URL. The video can be up to 100 MB. Do not mix video with other media. Do not upload first when the media URL is already public.
Use client.request to capture the durable write action. Send a unique Idempotency-Key. Store id, request.hash, billing, result, and statusUrl. Poll while terminal is false. Retry only when safeToRetry is true, using a new key.reply_to_tweet_id.media.media_id as the only media_ids item.write_action_id and charged_credits. Before retrying a pending tweet or reply, poll Get Write Action Status. client.x.tweets.create returns tweet.tweet_id for confirmed-only flows. client.x.media.upload returns media.media_id for DM attachments. client.x.dm.send_ returns dm.message_id for support tickets, CRM records, queue jobs, or agent memory. Keep DM body text in private systems. Shared logs, public artifacts, queue status, and agent handoffs should omit full DM bodies. They should store message_id, optional media_id, account, user_id, and send status. Leave generated reply_to_message_id unset even if SDK params expose it. The REST endpoint rejects DM reply threading.
client.x.dm.delete_message deletes a DM.
Text-only tweet and reply writes cost 30 credits. Tweet media adds 2 credits per started MB across attached files. Uploading media costs 10 credits. Sending the DM costs 10 credits. Do not pass uploaded media.media_id values to client.x.tweets.create. That method uses media with public media URLs.