TwitterAPIs Docs
API ReferenceWrite Actions

Create Draft Tweet API

Save a draft tweet on the account behind your registered session. A draft is private to that account and is never published: it appears in X's own composer under Drafts until you post or delete it. Accepts text, up to 4 media_ids, a reply_to and a quote, exactly like tweet/create. Billed at $0.0016 per call. Cost: $0.0016 per call.

POST draft/create saves a private draft tweet on the account behind your registered twitterapis session. Nothing is posted: the draft appears in X's own composer under Drafts until you publish or delete it. It takes text plus optional media_ids, reply_to and quote, and returns ok and draft_tweet_id for $0.0016 a call.

POST
/draft/create

Authorization

bearerAuth
AuthorizationBearer <token>

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/draft/create" \  -H "Content-Type: application/json" \  -d '{    "text": "Draft: our Q1 changelog is nearly done."  }'
{  "ok": true,  "draft_tweet_id": "2086650228950683648"}
{  "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

UnitPrice
Per call$0.0016
Per 1,000 calls$1.60

When to use

Use draft/create when a human still has to approve the wording before anything goes public, so the copy sits in X's own composer rather than in your database. Reach for tweet/create when the post should go out immediately, and scheduled/create when it should go out on its own at a known future time.

Notes

  • A draft is PRIVATE. It is never posted by this endpoint or by any timer; only you posting it from X's composer publishes it.
  • Needs a session for the account you are acting 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.
  • Upload media via media/upload first to get media_ids; up to 4 images per draft.
  • A 19-digit reply_to or quote sent as an UNQUOTED JSON number is refused rather than silently rounded to a different tweet. Send IDs as strings.

FAQ

Does creating a draft post anything to my timeline?

No. A draft is private to the account that owns it and stays in X's composer under Drafts. Nothing is published until you post it yourself, and there is no timer attached to a draft. Use scheduled/create if you want a post to go out on its own.

Can I create a draft with only an image and no text?

No. This endpoint refuses a draft with no text and answers 400 with a bad_request body. Put at least a placeholder line in text, then attach media_ids alongside it.

What happens if X refuses the create?

draft_tweet_id comes back null, the response is 422 rather than a misleading 200, and the call is not billed. Check ok before reading draft_tweet_id.