Pin a Tweet API | Pin a Post to Your X Profile
Pin a tweet to the top of the authenticated account's profile. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.
Pin Tweet pins one of your own tweets to the top of your X profile, acting as your authenticated account. It requires a registered X session and returns ok:true with changed:true once X confirms the pin. Pass the tweet id or url as a query parameter. This is a write action billed at $0.0008 per call, the same as a standard read.
Authorization
bearerAuth Pass your API key as a bearer token on every request: Authorization: Bearer <API_KEY>.
In: header
Query Parameters
Numeric ID of the tweet to pin. Provide either id or url.
Full status URL of the tweet to pin. Provide either id or url.
Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/tweet/pin?id=1759123456789012345&url=https%3A%2F%2Fx.com%2Fnaval%2Fstatus%2F1759123456789012345"{ "ok": true, "changed": true, "action": "pin", "target_id": "1759123456789012345"}{ "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."}{ "ok": false, "changed": false, "reason": "no_op_declined", "retryable": false, "detail": { "data": { "pin_tweet": {} } }, "action": "pin", "target_id": "1759123456789012345"}{ "error": "write_cap_reached", "reason": "write_cap_reached", "message": "This session has reached its daily write limit of 50 writes. The limit counts each stored or per-call session on your API key separately and resets at 00:00 UTC (see Retry-After). Nothing was sent to X and this call is not charged.", "daily_write_limit": 50, "retry_after_seconds": 43200, "action": "favorite", "target_id": "1759123456789012345"}{ "error": "server_error", "message": "Something failed on our side. Retry with backoff; if it persists, contact support."}Pricing
| Unit | Price |
|---|---|
| Per call | $0.0008 |
| Per 1,000 calls | $0.80 |
Writes are billed at $0.0008 per call, the same as a standard read. A change X confirms is billed, and so is an answer where X reports the post is already in that state (ok true, changed false); a 422 not-applied answer, an X error and a call that fails before reaching X are free.
When to use
Use it to feature a post on your profile programmatically, for example pinning a launch announcement the moment it goes out.
Notes
- Success is read from X's own confirmation that the post was pinned. Any other successful answer from X is returned as 422 with ok false, changed false and X's body in detail, and is not billed. An error status from X is answered like the other writes: 401 for a dead session, 403 when forbidden, 429 when rate limited and 502 for an upstream error.
- A profile has one pinned post. Pinning a tweet while another one is pinned replaces the earlier pin, so there is no need to unpin first.
- Needs a session for the account you are acting as: register one once (POST /customer/session), or pass per-call x-auth-token and x-ct0 headers. Returns 409 session_required if neither is supplied.
- This call counts toward a daily write limit per stored or per-call session on your API key, 50 writes per UTC day by default, shared by the like, retweet, bookmark, follow and pin calls and their undos. At the limit the call answers 429 write_cap_reached with a Retry-After header to the next 00:00 UTC. Nothing is sent to X and the call is not billed. daily_write_limit in the body is the limit in force. Retrying before the reset gets the same answer.
Related endpoints
- Unpin Tweet: Remove the pinned tweet from the authenticated account's profile.
- Create Tweet: Post a tweet as your registered account: text, media, reply, or quote.
- Like Tweet: Like (favorite) a tweet on behalf of an authenticated account.
FAQ
Do I need a session to pin a tweet?
Yes. Pinning changes your own profile, so it runs as your X account and needs a registered session or per-call credentials. Without one the call returns session_required and is not billed.
How do I remove a pin?
Call Unpin Tweet (tweet/unpin) with the same tweet id or url.
What does a 422 no_op_declined mean?
X answered without an error but did not confirm the pin, so nothing is billed. detail carries X's own body so you can see what it said.
Unlike Tweet POST
Remove a previously recorded like from a tweet as the authenticated account. Requires a logged-in session. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.
Unpin Tweet POST
Remove a pinned tweet from the authenticated account's profile. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.