Unpublish Article API
Revert a Published article back to Draft, identified by its entity id. The announcement tweet the original publish posted is left in place; use Delete Article to remove it too. X server-validates this transition and returns a 422 (invalid_lifecycle) if the article is not currently Published. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.
POST article/unpublish reverts a Published article back to Draft status without deleting its announcement tweet. It requires a registered session and the article's base64 entity id. It returns 422 if the article is not currently Published, and on success returns ok: true plus the updated article object. Billed at $0.0016 per call.
Authorization
bearerAuth Pass your API key as a bearer token on every request: Authorization: Bearer <API_KEY>.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/article/unpublish" \ -H "Content-Type: application/json" \ -d '{ "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4" }'{ "ok": true, "article": { "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4", "rest_id": "2086650228950683648", "title": "Why we rebuilt our onboarding from scratch", "preview_text": "Opening paragraph.", "lifecycle": "Draft", "content_state": { "blocks": [ { "key": "a1b2c", "text": "Opening paragraph.", "type": "unstyled", "depth": 0, "inlineStyleRanges": [], "entityRanges": [] } ], "entityMap": [] }, "cover_media": null, "media_entities": [], "author": { "id": "44196397", "username": "elonmusk", "name": "Elon Musk" }, "created_at_secs": 1786400000, "modified_at_secs": 1786400500, "first_published_at_secs": 1786400400, "visibility_setting": null, "tweet_id": "2086650300012345678", "public_url": null }}{ "error": "bad_request", "message": "Missing or malformed parameter. Fix the request before retrying."}{ "error": "unauthorized", "message": "The API key is missing, malformed, or revoked. Check the Authorization header."}{ "error": "insufficient_credits", "message": "Your balance is exhausted. Top up your credits to continue."}{ "error": "forbidden", "message": "The acting account is not authorized for this write action, or has no logged-in session."}{ "error": "not_found", "message": "The resource does not exist, for example a deleted tweet or a private account."}{ "error": "rate_limited", "message": "Too many requests. Back off and retry with exponential backoff."}{ "error": "server_error", "message": "Something failed on our side. Retry with backoff; if it persists, contact support."}Pricing
| Unit | Price |
|---|---|
| Per call | $0.0016 |
| Per 1,000 calls | $1.60 |
When to use
Use this endpoint when a published article needs to be pulled back to Draft for edits or review while keeping its original announcement tweet intact. Reach for Delete Article instead if the tweet itself also needs to come down.
Notes
- [VERIFY] Request variable names inferred; the 422 invalid_lifecycle validation is server-side on X's end, not executed live end-to-end.
- The announcement tweet from the original publish is left in place. To remove it too, call Delete Article instead.
- Returns 422 if the article is not currently Published (for example, it is already a Draft).
- Needs a session for the account you are writing as: either register one once (POST /customer/session), or pass per-call inline credentials as x-auth-token and x-ct0 request headers, which let a single API key act as many accounts. Returns 409 session_required if neither is supplied, 401 session_dead when the session has expired.
Related endpoints
- Publish Article: Publish a draft article. This posts a real, public announcement tweet.
- Delete Article: Delete an article. A draft is hard-deleted; a published article is unpublished, then its announcement tweet is removed too.
- Update Article Content: Replace an article's body with a new Draft.js content_state.
FAQ
Does unpublishing an article also remove the tweet that announced it?
No. The announcement tweet stays live. article/unpublish only reverts the article's status to Draft. If you need the tweet gone as well, call Delete Article instead, which removes both.
What happens if I call this on an article that's already a Draft?
The endpoint returns a 422 error. It only succeeds on articles currently in Published status, so check the article's status (via Get Article or List Articles) before calling this if you're not certain of its current state.
Publish Article POST
Publish a draft article as the account behind your registered session, transitioning it from Draft to Published. WARNING: publishing posts a real, public announcement tweet on the account's timeline. This is not a preview or a private action, and it cannot be undone by re-editing the article: once published, the only way back is Delete Article, which unpublishes the article AND removes the announcement tweet. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.
Get Article GET
Read an article's full content. Two mutually exclusive forms: id or url (the announcement tweet id or status URL) for a public, pooled read that needs no session, works for Published articles only. Or article_id (the article's own entity id, from Article Create or Article List) for an owner-only read that requires a registered session and also works for your own Drafts. Billed at $0.0008 per call. Cost: $0.0008 per call.