X (Twitter) API
Postproxy publishes tweets, native polls, and tweet chains (threads) to X. X is a bring-your-own-keys integration — you connect your own developer app. There is no comment or direct-message API.
Every request below uses the base URL https://api.postproxy.dev and an Authorization: Bearer YOUR_API_KEY header. Replace YOUR_API_KEY and the example IDs with your own.
Profiles and profile groups
Section titled “Profiles and profile groups”Every post targets one or more profiles. A profile is one connected account — for X (Twitter), an X account. Reference one in a request by its id (the prof_abc123 in the examples below) or by the platform name "twitter", which selects the group’s X (Twitter) profile (a group holds at most one profile per platform). List what’s connected with GET /api/profiles.
Profiles live in profile groups — containers that organize the accounts for one brand, client, or project. List groups with GET /api/profile_groups, and connect a new X (Twitter) profile with the Initialize Connection endpoint.
Example: get profiles and profile groups
List the profiles you can post to — GET /api/profiles:
curl -X GET "https://api.postproxy.dev/api/profiles" \ -H "Authorization: Bearer YOUR_API_KEY"{ "data": [ { "id": "prof_abc123", "name": "@mycompany", "platform": "twitter", "status": "active", "profile_group_id": "grp_xyz789", "expires_at": null, "post_count": 127, "avatar_url": "https://cdn.postproxy.dev/uploads/avatar_prof_abc123.jpg" } ]}List your profile groups — GET /api/profile_groups:
curl -X GET "https://api.postproxy.dev/api/profile_groups" \ -H "Authorization: Bearer YOUR_API_KEY"{ "data": [ { "id": "grp_xyz789", "name": "Main Brand", "profiles_count": 5 }, { "id": "grp_def456", "name": "Client Project", "profiles_count": 3 } ]}At a glance
Section titled “At a glance”| Platform ID | twitter |
| Formats | post (default), poll |
| Character limit | 280 (free) / 25,000 (paid); polls always 280 |
| Media | Optional (post); not allowed (poll) |
| Comments | No |
| Direct messages | No |
| Post chains | Yes |
Publishing
Section titled “Publishing”Formats
Section titled “Formats”| Format | Description |
|---|---|
post | Tweet (default). Content type is inferred from the attached media |
poll | Tweet with a native poll |
Tweet (post)
Section titled “Tweet (post)”The post format has no custom parameters.
| Media | Max size | Formats | Count | Duration |
|---|---|---|---|---|
| Image | 5 MB | jpg, png, webp, gif | 4 | — |
| Video | 512 MB | mp4, mov | 1 | 1 s – 140 s |
- Text-only tweets are allowed; media is optional.
- Images and video cannot be mixed.
- Minimum image dimensions 4×4 px; minimum video dimensions 32×32 px.
# Tweet with an imagecurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Just shipped a new feature! Check it out 🎉" }, "profiles": ["prof_abc123"], "media": ["https://example.com/image.jpg"], "platforms": { "twitter": {} } }'Poll (poll)
Section titled “Poll (poll)”| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | Yes | "poll" |
poll_options | array of strings | Yes | 2–4 choices, max 25 characters each |
poll_duration_minutes | integer | Yes | 5 to 10,080 (7 days) |
Polls are capped at 280 characters and cannot include media or be part of a thread.
# Pollcurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Which framework do you prefer?" }, "profiles": ["prof_abc123"], "platforms": { "twitter": { "format": "poll", "poll_options": ["Rails", "Django", "Laravel", "Other"], "poll_duration_minutes": 1440 } } }'Post chains (threads)
Section titled “Post chains (threads)”X supports threads for the post format. Pass a thread array of follow-up tweets; each child can carry its own media. Polls cannot be threaded.
# A tweet threadcurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "1/ A short thread on what we learned 🧵" }, "profiles": ["prof_abc123"], "thread": [ { "body": "2/ Ship small, ship often." }, { "body": "3/ Talk to users every week.", "media": ["https://example.com/chart.png"] } ] }'Comments
Section titled “Comments”Not supported through the API.
Direct messages
Section titled “Direct messages”Not supported.
Postproxy records periodic stat snapshots you can pull as a timeseries; field names pass through from X unchanged.
Profile stats
Section titled “Profile stats”Account-level metrics, refreshed roughly every 23 hours via the Profile stats endpoint (GET /api/profiles/:id/stats).
Fields: followers_count, following_count, tweet_count, listed_count, like_count
# Fetch the profile stats timeseriescurl "https://api.postproxy.dev/api/profiles/prof_abc123/stats" \ -H "Authorization: Bearer YOUR_API_KEY"Post stats
Section titled “Post stats”Per-tweet engagement, captured after publish via the Post stats endpoint (GET /api/posts/stats).
Fields: impressions, likes, retweets, comments, quotes, saved
# Fetch post statscurl "https://api.postproxy.dev/api/posts/stats?post_ids=post_abc123&profiles=twitter" \ -H "Authorization: Bearer YOUR_API_KEY"Webhooks
Section titled “Webhooks”Subscribe with the Webhooks API:
curl -X POST "https://api.postproxy.dev/api/webhooks" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/webhooks/postproxy", "events": ["platform_post.published", "platform_post.failed", "platform_post.insights"] }'Events relevant to X:
| Event | When |
|---|---|
post.processed | A post is ready to publish |
platform_post.published | A post was published to the platform |
platform_post.failed | A post failed to publish (retries exhausted) |
platform_post.failed_waiting_for_retry | A publish attempt failed; will retry |
platform_post.insights | New analytics snapshot |
profile.connected / .disconnected | Connection state changed |
profile.stats | New profile stats snapshot |
media.failed | A media attachment failed to process |
- The character limit depends on your X account tier: 280 on free, 25,000 on paid. Polls are always capped at 280.
- X requires your own API keys — see the X bring-your-own-keys guide.
poll, media, and threads are mutually exclusive.