Update Profile API
Update the profile of the account behind your registered session. Send only the fields you want to change: this is a genuine PARTIAL update, and anything you omit is left exactly as it was rather than being blanked. At least one of name, description, location or url is required. Billed at $0.0016 per call. Cost: $0.0016 per call.
POST user/update_profile changes the display name, bio, location or link on the account behind your registered twitterapis session. It is a PARTIAL update: omitted fields keep their current values rather than being cleared, so you can send just a name. At least one field is required. It returns ok and updated_fields, and costs $0.0016 a 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/user/update_profile" \ -H "Content-Type: application/json" \ -d '{}'{ "ok": true, "updated_fields": [ "name" ]}{ "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.", "top_up_url": "https://www.twitterapis.com/dashboard/buy-credits?utm_source=api&utm_medium=402"}{ "error": "forbidden", "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."}{ "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 it to change your own profile text, for example keeping a bio in sync with a status your system already tracks. It only ever writes the account behind your session; there is no way to edit anyone else's profile, and reading any public profile is user/info instead.
Notes
- A PARTIAL update, verified rather than assumed: sending only
nameagainst an account with a non-empty bio returned 200 and left the bio intact. X's own web client sends the whole editable set on every save, so the partial form is a shape its client never sends, which is why this was tested before being published. - An empty string CLEARS a field, and an omitted field is left alone. A request whose only value is an empty string is a valid clear, not an empty request. This was the other way round until 2026-09-13: the handler trimmed empty values before anything downstream could tell them apart, so a clear was silently impossible and a request pairing a real field with an empty one answered 200 while dropping the empty one. Verified live on a real account after the fix, by reading the profile back rather than trusting the response.
- At least one of name, description, location or url is required. A request carrying none of them is refused with 400 rather than sent upstream.
- 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.
- This writes your own profile and takes effect immediately on x.com. There is no undo; read your current values with user/info first if you need to restore them.
Related endpoints
- User Info by Username: Fetch a full profile by @handle.
- Register Session: Register your auth_token and ct0 cookies once so every write and private read acts as your account, or pass them per call as x-auth-token / x-ct0 headers.
- Create Tweet: Post a tweet as your registered account: text, media, reply, or quote.
FAQ
Will sending only a name wipe my bio?
No. Omitted fields are preserved. That was tested directly on an account with a non-empty bio before this endpoint was published: name only, HTTP 200, bio unchanged. Clearing is deliberate and explicit: send an empty string for the field you want to blank, and only that field is affected.
Can I update someone else's profile?
No. The call acts as the account behind your registered session or your per-call inline credentials, and there is no parameter that names a different account.
What does updated_fields tell me?
Which field names your request carried. It is an echo of what you submitted rather than a diff, so a field you set to the value it already held is still listed. Read the profile back with user/info if you need to confirm the resulting state.
List Scheduled Tweets GET
List every pending scheduled post on the account behind your registered session. Each row carries the id, its text, its execute_at in epoch SECONDS, X's own state label, and thread_truncated for a thread whose text is only its first tweet. Ordering is X's: pass ascending=true to ask for the oldest first. Billed at $0.0016 per call. Cost: $0.0016 per call.
Update Avatar POST
Replace the profile picture on the account behind your registered session. Send the image base64-encoded in the request body; there is no URL-fetch form and no multipart form. Billed at $0.0016 per call. Cost: $0.0016 per call.