Twitter/X API
Schedule and automate Twitter/X posts with Zernio API - Tweets, threads, images, videos, and GIFs
Quick Reference
| Property | Value |
|---|---|
| Character limit | 280 (free) / 25,000 (Premium) |
| Images per post | 4 (or 1 GIF) |
| Videos per post | 1 |
| Image formats | JPEG, PNG, WebP, GIF |
| Image max size | 5 MB (images), 15 MB (GIFs) |
| Video formats | MP4, MOV |
| Video max size | 512 MB |
| Video max duration | 140 seconds |
| Threads | Yes (via threadItems) |
| Scheduling | Yes |
| Inbox (DMs) | Yes (add-on) |
| Inbox (Comments) | Yes (add-on) |
| Analytics | Yes |
Before You Start
Twitter has a strict 280 character limit for free accounts. URLs always count as 23 characters regardless of actual length. Emojis count as 2 characters. If you're cross-posting from platforms with higher limits (LinkedIn 3,000, Facebook 63,000), use customContent to provide a shorter Twitter version or your post WILL fail.
Additional requirements:
- Duplicate tweets are rejected (even very similar content)
- Free accounts: 280 characters, Premium accounts: 25,000 characters
Quick Start
Post a tweet in under 60 seconds:
const { post } = await zernio.posts.createPost({
content: 'Hello from Zernio API!',
platforms: [
{ platform: 'twitter', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Tweet posted!', post._id);result = client.posts.create(
content="Hello from Zernio API!",
platforms=[
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Tweet posted! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Hello from Zernio API!",
"platforms": [
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Content Types
Text Tweet
A simple text-only tweet. Keep it under 280 characters for free accounts.
const { post } = await zernio.posts.createPost({
content: 'Just shipped a new feature. Check it out!',
platforms: [
{ platform: 'twitter', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Tweet posted!', post._id);result = client.posts.create(
content="Just shipped a new feature. Check it out!",
platforms=[
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Tweet posted! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Just shipped a new feature. Check it out!",
"platforms": [
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Tweet with Image
Attach up to 4 images per tweet. JPEG, PNG, WebP, and GIF formats are supported.
const { post } = await zernio.posts.createPost({
content: 'Check out this photo!',
mediaItems: [
{ type: 'image', url: 'https://cdn.example.com/photo.jpg' }
],
platforms: [
{ platform: 'twitter', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Tweet with image posted!', post._id);result = client.posts.create(
content="Check out this photo!",
media_items=[
{"type": "image", "url": "https://cdn.example.com/photo.jpg"}
],
platforms=[
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Tweet with image posted! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Check out this photo!",
"mediaItems": [
{"type": "image", "url": "https://cdn.example.com/photo.jpg"}
],
"platforms": [
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Tweet with Video
Attach a single video per tweet. MP4 and MOV formats, up to 512 MB, max 140 seconds (standard uploads).
const { post } = await zernio.posts.createPost({
content: 'New product demo',
mediaItems: [
{ type: 'video', url: 'https://cdn.example.com/demo.mp4' }
],
platforms: [
{ platform: 'twitter', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Tweet with video posted!', post._id);result = client.posts.create(
content="New product demo",
media_items=[
{"type": "video", "url": "https://cdn.example.com/demo.mp4"}
],
platforms=[
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Tweet with video posted! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "New product demo",
"mediaItems": [
{"type": "video", "url": "https://cdn.example.com/demo.mp4"}
],
"platforms": [
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Tweet with GIF
Only 1 GIF per tweet (it consumes all 4 image slots). Max 15 MB, 1280 x 1080 px. Animated GIFs auto-play in the timeline.
const { post } = await zernio.posts.createPost({
content: 'Check out this animation!',
mediaItems: [
{ type: 'gif', url: 'https://cdn.example.com/animation.gif' }
],
platforms: [
{ platform: 'twitter', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Tweet with GIF posted!', post._id);result = client.posts.create(
content="Check out this animation!",
media_items=[
{"type": "gif", "url": "https://cdn.example.com/animation.gif"}
],
platforms=[
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Tweet with GIF posted! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Check out this animation!",
"mediaItems": [
{"type": "gif", "url": "https://cdn.example.com/animation.gif"}
],
"platforms": [
{"platform": "twitter", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Thread (Multi-Tweet)
Create Twitter threads with multiple connected tweets using platformSpecificData.threadItems. Each item becomes a reply to the previous tweet and can have its own content and media.
Note: When
threadItemsis provided, the top-levelcontentfield is used only for display and search purposes — it is NOT published. You must include your first tweet asthreadItems[0].
Reply Tweets
Use platformSpecificData.replyToTweetId to publish a tweet as a reply to an existing tweet.
Note:
replyToTweetIdcannot be combined withreplySettings. For threads, only the first tweet replies to the target; subsequent tweets chain normally.
curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Replying via Zernio API",
"platforms": [{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"replyToTweetId": "1748391029384756102"
}
}],
"publishNow": true
}'const { post } = await zernio.posts.createPost({
content: 'Replying via Zernio API',
platforms: [{
platform: 'twitter',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
replyToTweetId: '1748391029384756102'
}
}],
publishNow: true
});
console.log('Reply posted!', post._id);result = client.posts.create(
content="Replying via Zernio API",
platforms=[{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"replyToTweetId": "1748391029384756102"
}
}],
publish_now=True
)
post = result.post
print(f"Reply posted! {post['_id']}")Reply Thread
To reply with a thread, combine replyToTweetId with threadItems. Only the first thread item replies to the target tweet.
curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": [{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"replyToTweetId": "1748391029384756102",
"threadItems": [
{"content": "1/ Reply thread: first tweet replies to the target"},
{"content": "2/ Follow-up tweet in the same thread"}
]
}
}],
"publishNow": true
}'const { post } = await zernio.posts.createPost({
platforms: [{
platform: 'twitter',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
replyToTweetId: '1748391029384756102',
threadItems: [
{ content: '1/ Reply thread: first tweet replies to the target' },
{ content: '2/ Follow-up tweet in the same thread' }
]
}
}],
publishNow: true
});
console.log('Reply thread posted!', post._id);result = client.posts.create(
platforms=[{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"replyToTweetId": "1748391029384756102",
"threadItems": [
{"content": "1/ Reply thread: first tweet replies to the target"},
{"content": "2/ Follow-up tweet in the same thread"}
]
}
}],
publish_now=True
)
post = result.post
print(f"Reply thread posted! {post['_id']}")const { post } = await zernio.posts.createPost({
platforms: [{
platform: 'twitter',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
threadItems: [
{
content: '1/ Starting a thread about API design',
mediaItems: [{ type: 'image', url: 'https://cdn.example.com/image1.jpg' }]
},
{ content: '2/ First, always use proper HTTP methods...' },
{ content: '3/ Second, version your APIs from day one...' },
{ content: '4/ Finally, document everything! /end' }
]
}
}],
publishNow: true
});
console.log('Thread posted!', post._id);result = client.posts.create(
platforms=[{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"threadItems": [
{
"content": "1/ Starting a thread about API design",
"mediaItems": [{"type": "image", "url": "https://cdn.example.com/image1.jpg"}]
},
{"content": "2/ First, always use proper HTTP methods..."},
{"content": "3/ Second, version your APIs from day one..."},
{"content": "4/ Finally, document everything! /end"}
]
}
}],
publish_now=True
)
post = result.post
print(f"Thread posted! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": [{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"threadItems": [
{
"content": "1/ Starting a thread about API design",
"mediaItems": [{"type": "image", "url": "https://cdn.example.com/image1.jpg"}]
},
{
"content": "2/ First, always use proper HTTP methods..."
},
{
"content": "3/ Second, version your APIs from day one..."
},
{
"content": "4/ Finally, document everything! /end"
}
]
}
}],
"publishNow": true
}'Media Requirements
Images
| Property | Requirement |
|---|---|
| Max images | 4 per tweet |
| Formats | JPEG, PNG, WebP, GIF |
| Max file size | 5 MB (images), 15 MB (GIFs) |
| Min dimensions | 4 x 4 px |
| Max dimensions | 8192 x 8192 px |
| Recommended | 1200 x 675 px (16:9) |
Aspect Ratios
| Type | Ratio | Dimensions |
|---|---|---|
| Landscape | 16:9 | 1200 x 675 px |
| Square | 1:1 | 1200 x 1200 px |
| Portrait | 4:5 | 1080 x 1350 px |
GIFs
| Property | Requirement |
|---|---|
| Max per tweet | 1 (consumes all 4 image slots) |
| Max file size | 15 MB |
| Max dimensions | 1280 x 1080 px |
| Behavior | Auto-plays in timeline |
Videos
| Property | Requirement |
|---|---|
| Max videos | 1 per tweet |
| Formats | MP4, MOV |
| Max file size | 512 MB |
| Max duration | 140 seconds (2 min 20 sec) standard; up to ~10 minutes with Premium long video (see below) |
| Min duration | 0.5 seconds |
| Min dimensions | 32 x 32 px |
| Max dimensions | 1920 x 1200 px |
| Frame rate | 40 fps max |
| Bitrate | 25 Mbps max |
Long Video Uploads (Premium)
By default, X limits API video uploads to 140 seconds. If the connected X account has an active X Premium subscription, you can enable long video uploads (over 140 seconds) by setting platformSpecificData.longVideo: true.
Note: Not all Premium accounts have API long-video access, as X may require separate allowlisting.
curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Long video upload (Premium)",
"mediaItems": [
{"type": "video", "url": "https://cdn.example.com/long-video.mp4"}
],
"platforms": [{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"longVideo": true
}
}],
"publishNow": true
}'const { post } = await zernio.posts.createPost({
content: 'Long video upload (Premium)',
mediaItems: [{ type: 'video', url: 'https://cdn.example.com/long-video.mp4' }],
platforms: [{
platform: 'twitter',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
longVideo: true
}
}],
publishNow: true
});
console.log('Tweet posted!', post._id);result = client.posts.create(
content="Long video upload (Premium)",
media_items=[{"type": "video", "url": "https://cdn.example.com/long-video.mp4"}],
platforms=[{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {"longVideo": True}
}],
publish_now=True
)
post = result.post
print(f"Tweet posted! {post['_id']}")Recommended Video Specs
| Property | Recommended |
|---|---|
| Resolution | 1280 x 720 px (720p) |
| Aspect ratio | 16:9 (landscape) or 1:1 (square) |
| Frame rate | 30 fps |
| Codec | H.264 |
| Audio | AAC, 128 kbps |
Platform-Specific Fields
All fields go inside platformSpecificData on the Twitter platform entry.
| Field | Type | Description |
|---|---|---|
replyToTweetId | string | ID of an existing tweet to reply to. The published tweet will appear as a reply in that tweet's thread. For threads, only the first tweet replies to the target; subsequent tweets chain normally. |
replySettings | "following" | "mentionedUsers" | "subscribers" | "verified" | Controls who can reply to the tweet. Omit for default (everyone can reply). For threads, applies to the first tweet only. Cannot be combined with replyToTweetId. |
threadItems | Array<{content, mediaItems?}> | Complete sequence of tweets in a thread. The first item becomes the root tweet and must be provided as threadItems[0]. When threadItems is provided, top-level content is for display/search only and is NOT published. |
poll | object | Create a poll with this tweet. Mutually exclusive with media attachments and threads. |
poll.options | string[] | Poll options (2-4 choices, max 25 characters each). |
poll.duration_minutes | number | Poll duration in minutes (5 min to 7 days). |
longVideo | boolean | Enable long video uploads (over 140 seconds) using amplify_video. Requires X Premium; may require allowlisting. |
geoRestriction | object | Restrict media visibility to specific countries. Only applies when media is attached (ignored for text-only tweets). geoRestriction.countries: array of uppercase ISO 3166-1 alpha-2 codes, max 25. The media is hidden in restricted countries; the tweet text remains visible globally. |
Geo-Restriction
Restrict who can see your tweet's media by country. This applies at the media level: the media is hidden for users outside the specified countries, but the tweet text remains visible globally. Requires media to be attached.
{
"platforms": [{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"geoRestriction": {
"countries": ["US", "ES"]
}
}
}],
"mediaItems": [{"type": "image", "url": "https://example.com/photo.jpg"}]
}Polls
Create a Twitter/X poll by providing platformSpecificData.poll.
Note: Polls are mutually exclusive with
mediaItemsandplatformSpecificData.threadItems.
curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Which feature should we ship next?",
"platforms": [{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"poll": {
"options": ["Dark mode", "New analytics", "More integrations"],
"duration_minutes": 1440
}
}
}],
"publishNow": true
}'const { post } = await zernio.posts.createPost({
content: 'Which feature should we ship next?',
platforms: [{
platform: 'twitter',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
poll: {
options: ['Dark mode', 'New analytics', 'More integrations'],
duration_minutes: 1440
}
}
}],
publishNow: true
});
console.log('Poll posted!', post._id);result = client.posts.create(
content="Which feature should we ship next?",
platforms=[{
"platform": "twitter",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"poll": {
"options": ["Dark mode", "New analytics", "More integrations"],
"duration_minutes": 1440
}
}
}],
publish_now=True
)
post = result.post
print(f"Poll posted! {post['_id']}")Media URL Requirements
These do not work as media URLs:
- Google Drive -- returns an HTML download page, not the file
- Dropbox -- returns an HTML preview page
- OneDrive / SharePoint -- returns HTML
- iCloud -- returns HTML
Test your URL in an incognito browser window. If you see a webpage instead of the raw image or video, it will not work.
Media URLs must be:
- Publicly accessible (no authentication required)
- Returning actual media bytes with the correct
Content-Typeheader - Not behind redirects that resolve to HTML pages
- Hosted on a fast, reliable CDN
Supabase URLs: Zernio auto-proxies Supabase storage URLs, so they work without additional configuration.
Analytics
Requires Analytics add-on
Available metrics via the Analytics API:
| Metric | Available |
|---|---|
| Impressions | ✅ |
| Likes | ✅ |
| Comments | ✅ |
| Shares | ✅ |
| Clicks | ✅ |
| Views | ✅ |
const analytics = await zernio.analytics.getAnalytics({
platform: 'twitter',
fromDate: '2024-01-01',
toDate: '2024-01-31'
});
console.log(analytics.posts);analytics = client.analytics.get(
platform="twitter",
from_date="2024-01-01",
to_date="2024-01-31"
)
print(analytics["posts"])curl "https://zernio.com/api/v1/analytics?platform=twitter&fromDate=2024-01-01&toDate=2024-01-31" \
-H "Authorization: Bearer YOUR_API_KEY"Engagement
Retweet, bookmark, and follow directly through the API. All engagement endpoints share a 50 requests per 15-min window rate limit. Retweets also share the 300/3hr creation limit with tweet creation.
// Retweet
await zernio.twitterEngagement.retweetPost({
accountId: 'YOUR_ACCOUNT_ID',
tweetId: '1748391029384756102'
});
// Bookmark
await zernio.twitterEngagement.bookmarkPost({
accountId: 'YOUR_ACCOUNT_ID',
tweetId: '1748391029384756102'
});
// Follow
await zernio.twitterEngagement.followUser({
accountId: 'YOUR_ACCOUNT_ID',
targetUserId: '123456789'
});# Retweet
client.twitter_engagement.retweet_post(
account_id="YOUR_ACCOUNT_ID",
tweet_id="1748391029384756102"
)
# Bookmark
client.twitter_engagement.bookmark_post(
account_id="YOUR_ACCOUNT_ID",
tweet_id="1748391029384756102"
)
# Follow
client.twitter_engagement.follow_user(
account_id="YOUR_ACCOUNT_ID",
target_user_id="123456789"
)# Retweet
curl -X POST https://zernio.com/api/v1/twitter/retweet \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountId": "YOUR_ACCOUNT_ID", "tweetId": "1748391029384756102"}'
# Bookmark
curl -X POST https://zernio.com/api/v1/twitter/bookmark \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountId": "YOUR_ACCOUNT_ID", "tweetId": "1748391029384756102"}'
# Follow
curl -X POST https://zernio.com/api/v1/twitter/follow \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountId": "YOUR_ACCOUNT_ID", "targetUserId": "123456789"}'| Action | Endpoint | Undo |
|---|---|---|
| Retweet | POST /v1/twitter/retweet | DELETE /v1/twitter/retweet |
| Bookmark | POST /v1/twitter/bookmark | DELETE /v1/twitter/bookmark |
| Follow | POST /v1/twitter/follow | DELETE /v1/twitter/follow |
See Twitter Engagement API Reference for full endpoint documentation.
Edit Published Tweets
Zernio supports editing published tweets via X's edit feature.
Note: Editing is currently supported for X (Twitter) only, requires an active X Premium subscription on the connected account, must be within 1 hour of the original publish time, is limited to 5 edits per tweet (enforced by X), and supports text-only edits (media changes are not supported).
curl -X POST https://zernio.com/api/v1/posts/YOUR_POST_ID/edit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "twitter",
"content": "Updated tweet text with corrected information"
}'const result = await zernio.posts.editPost({
postId: 'YOUR_POST_ID',
platform: 'twitter',
content: 'Updated tweet text with corrected information'
});
console.log('Edited tweet:', result.id, result.url);result = client.posts.edit_post(
post_id="YOUR_POST_ID",
platform="twitter",
content="Updated tweet text with corrected information"
)
print("Edited tweet:", result["id"], result["url"])What You Can't Do
These features are not available through Twitter's API:
- Create Spaces
- Post to Communities
- Pin tweets to profile
- Add Twitter Cards (must be configured on the destination URL via meta tags)
- Post as a personal DM broadcast
Common Errors
Twitter/X has a 21.3% failure rate across Zernio's platform (17,385 failures out of 81,796 attempts). Here are the most frequent errors and how to fix them:
| Error | What it means | How to fix |
|---|---|---|
| "Tweet text is too long (X characters). Twitter's limit is 280 characters. Note: URLs count as 23 characters." | Exceeds 280 character limit for free accounts | Shorten text or use customContent for Twitter. Remember: URLs = 23 chars, emojis = 2 chars. |
| "X (Twitter) does not allow duplicate tweets" | Same or very similar content was already posted | Modify the text, even slightly. |
| "Rate limit hit. Please wait 10 minutes" | Zernio's velocity limit was triggered | Reduce posting frequency. Space posts at least 4 minutes apart. |
| "Missing tweet.write scope" / "forbidden" | OAuth token lacks required permissions | Reconnect the account with all required scopes. |
| Token expired | OAuth access was revoked or expired | Reconnect the account. Subscribe to the account.disconnected webhook to catch this proactively. |
Inbox
Requires Inbox add-on — Build: +$10/mo · Accelerate: +$50/unit · Unlimited: +$1,000/mo
Twitter/X supports DMs and comments through the unified Inbox API.
Direct Messages
| Feature | Supported |
|---|---|
| List conversations | ✅ |
| Fetch messages | ✅ |
| Send text messages | ✅ |
| Send attachments | ✅ (images, videos - max 25 MB) |
| Archive/unarchive | ❌ |
Create conversation (send a DM)
Use POST /v1/inbox/conversations to start a new DM conversation (or append to an existing thread).
Note: X DM write endpoints require X API Pro tier ($5,000/month) or Enterprise access. This applies to BYOK users who provide their own X API credentials.
Note: By default, Zernio checks DM eligibility (recipient
receives_your_dm). If the recipient does not accept DMs, the API returns422with codeDM_NOT_ALLOWED. You can skip this check withskipDmCheck: true.
curl -X POST https://zernio.com/api/v1/inbox/conversations \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "YOUR_ACCOUNT_ID",
"participantUsername": "targetuser",
"message": "Hello from Zernio Inbox API!"
}'const result = await zernio.messages.createConversation({
accountId: 'YOUR_ACCOUNT_ID',
participantUsername: 'targetuser',
message: 'Hello from Zernio Inbox API!'
});
console.log('DM sent:', result.data.conversationId, result.data.messageId);result = client.messages.create_conversation(
account_id="YOUR_ACCOUNT_ID",
participant_username="targetuser",
message="Hello from Zernio Inbox API!"
)
print("DM sent:", result["data"]["conversationId"], result["data"]["messageId"])Comments
| Feature | Supported |
|---|---|
| List comments on posts | ✅ |
| Post new comment | ✅ |
| Reply to comments | ✅ |
| Delete comments | ✅ |
| Like/unlike comments | ✅ |
| Hide/unhide comments | ✅ |
Limitations
- Encrypted X Chat DMs not accessible - X has replaced traditional DMs with end-to-end encrypted "X Chat" for many accounts. Messages sent or received through encrypted X Chat are not returned by X's API. This means some conversations may show only outgoing messages or appear empty. This is an X platform limitation that affects all third-party applications.
- DM permissions - DMs require
dm.readanddm.writescopes - Reply search - Uses cached conversation threads (2-min TTL) to manage rate limits
- Cached DMs - Conversations are cached with a 15-min TTL
See Messages and Comments API Reference for endpoint details.
Related Endpoints
- Connect Twitter Account - OAuth flow
- Create Post - Post creation and scheduling
- Upload Media - Image and video uploads
- Analytics - Post performance metrics
- Twitter Engagement - Retweet, bookmark, follow
- Messages and Comments