PPactDocs
Productivity

X (Twitter)

Connect an X account to Pact's social studio — OAuth 2.0 PKCE, text posting, replies, and per-tweet analytics, with the current tier and media limits spelled out.

X (Twitter)

X is one of Pact's social studio providers. Once connected, you can publish and schedule text posts, reply to tweets, pull per-tweet analytics, and delete posts — all through the same /v1/social/* routes that drive LinkedIn, Threads, Bluesky, and the rest. The provider talks to the X v2 API using OAuth 2.0 with PKCE.

Partial — real, but with real limits

The X adapter genuinely calls the live X v2 API: connect, post, reply, analytics, and delete are implemented (core/integrations/social/twitter/). But posting is text-only today, engagement polling and mention ingestion are stubbed, and direct messages are not supported. It also depends on you bringing your own X app credentials and a paid X tier — see below.

What works today

CapabilityStatus
Connect via OAuth 2.0 (PKCE)Live — authorize_url + complete_oauth + token refresh
Publish a text postLive — POST /2/tweets, truncated to 280 chars
Reply to a tweetLive — reply with in_reply_to_tweet_id
Per-post analyticsLive — reads public_metrics (impressions, likes, replies, retweets)
Delete a postLive — deletes on-platform and soft-deletes in Pact
Image / video uploadNot yet — media_urls is ignored; follows the v1.1 media flow later
Engagement + mention pollingStubbed — returns empty until the listening worker is wired
Direct messagesNot supported — requires a paid tier above Basic

Connecting an account

Account connect/disconnect is admin/owner-only (it touches the credential store); any user can create posts once an account is connected.

bash
# Start OAuth — returns an authorize_url to send the admin to
curl -s -X POST "https://api.pact.place/v1/social/twitter/connect" \
  -H "Authorization: Bearer $PACT_API_KEY"

The callback (GET /v1/social/twitter/callback) completes the PKCE exchange and redirects back to the app. Tokens are stored in the credential store, never in audit payloads. Every connect/disconnect/refresh writes an audit event (social.account.connected, .disconnected, .token_refreshed, …).

Bring your own X app

X gates the v2 API behind paid tiers. Pact treats X as opt-in: the Connect button surfaces a "requires X Basic tier (~$100/mo)" notice, and you supply your own X app's client_id / client_secret — resolved per tenant from the credential store (credential key oauth_app_twitter), or from TWITTER_CLIENT_ID / TWITTER_CLIENT_SECRET as a fallback.

  • Basic (~$100/mo): 100k reads + 50k writes per month — the practical floor.
  • Pro ($5k/mo): higher quotas plus real-time Filtered Stream.
  • Free: 1,500 posts / 24h, no Filtered Stream.

The default OAuth scopes are tweet.read, tweet.write, users.read, and offline.access.

Rate limits are surfaced, not swallowed

When X returns a 429, the provider raises a rate-limit error carrying the x-rate-limit-reset retry-after so the scheduler can back off cleanly rather than hammering the API.