Read X profiles and post history

Use a connected account to read its current X profile and walk authored posts without exposing credentials, crossing Managed User boundaries, or duplicating a paid read.

X onlyServer-side API keyIdempotent readsCursor pagination

1. Verify the connection and ownership boundary

Keep the UniPost API key on your server and derive external_user_id from the authenticated app user. It must match the Managed User that owns the connected account. The connection must retain its persisted X app identity: UniPost-managed credentials stay managed, while a workspace-owned X app stays customer-owned.

Follow Authentication to send the Bearer token securely from your server.

The profile read requires users.read and offline.access. Authored post history also requires tweet.read. Call Get account capabilities first. If the response reports reconnect_required or the read returns ACCOUNT_REAUTHORIZATION_REQUIRED, follow the X reconnect guide.

2. Read the live profile

Choose a caller-owned Idempotency-Key for this logical read. An exact retry uses the same key and identical account and external_user_id. A different read uses a new key. See the profile API Reference for the complete response envelope.

3. Read the first authored-post page

Set limit from 5 through 100. start_time is inclusive and end_time is exclusive. Reposts and replies-to-others are filtered after the upstream scan, so meta.returned_count can be smaller than meta.scanned_count. See the authored posts API Reference for all normalized post fields.

Setting exclude_replies_to_others=true excludes replies to other users while preserving self-replies for thread continuity.

4. Continue with an opaque cursor

When meta.next_cursor is present, submit it with the same time bounds, filters, account, and Managed User. That cursor selects a new logical page, so give it a new logical-page key. If the network result is uncertain, retry that exact page with the same key. Do not decode or edit cursors, and do not reuse a key across a different cursor or filter set.

Enforce durable deduplication by external_post_id across pages and retries before storing or processing each post.

Cursors expire. INVALID_CURSOR means restart from a new first page. If a retriable error includeserror.details.retry_cursor and retry_cursor_expires_at, use that cursor with the same logical-page key.

5. Handle retries by stable error code

Read error.code, error.is_retriable, the HTTP Retry-After header, andrequest_id. Preserve the original key and exact parameters for retriable states; never rotate a key merely because a timeout made the outcome uncertain. See the general Errors reference for the response shape.

  • VALIDATION_ERROR or IDEMPOTENCY_KEY_REQUIRED: correct the request before sending a new logical operation.
  • ACCOUNT_NOT_FOUND, WRONG_PLATFORM, or ACCOUNT_ACCESS_DENIED: re-check the account and Managed User boundary.
  • ACCOUNT_REAUTHORIZATION_REQUIRED: reconnect the X account with the required scopes.
  • INVALID_CURSOR: start a fresh traversal unless a supplied retry cursor is still valid.
  • IDEMPOTENCY_CONFLICT: the key was reused with different inputs; create a new logical key for the corrected request.
  • READ_IN_PROGRESS or READ_SETTLEMENT_PENDING: wait for Retry-After, then retry with the same key.
  • RATE_LIMITED or X_UPSTREAM_ERROR: retry only when is_retriable is true.

6. Inspect Credits policy and receipts

Customer X Credits accounting is disabled by the current rollout flag. Reads remain available and return meta.credits.accounting_enabled=false with bypass_reason=feature_disabled. Workspace-owned X credentials return bypass_reason=customer_x_app. These bypass states do not remove X provider rate limits or authorization requirements.