lukhed_x
A custom tweepy wrapper for the X API v2 with built-in key management via LukhedAuth.
Used by @grindSunday and @popPunkPoets bots.
Features
- X API v2: v1.1 endpoints are gone, this wrapper is v2 only
- Flexible Key Management: Store API credentials locally or in a private GitHub repo
- Cost Aware: every method documents what it costs to call
- Posts, Users, Engagement, Lists, DMs and Media
Installation
pip install lukhed-x
Costs
X retired the free tier in 2026. Every call costs credits, which you buy at console.x.com. Full table: X API pricing.
The one to watch:
| Action | Cost |
|---|---|
| Create a post | $0.015 |
| Create a post containing a URL | $0.200 |
| Owned reads (your own posts, followers, mentions, lists) | $0.001 |
| Post / list reads | $0.005 |
| User and follower reads | $0.010 |
| Likes, reposts, follows, mutes, DMs | $0.015 |
| Undoing any of those | $0.010 |
A link in your post text costs 13x a plain post. Keep URLs out of automated posts unless you mean it.
Set a spending cap in the developer console before running any bot.
Quick Start
Initial Setup
from lukhed_x import X
# First run prompts for your X API credentials, then stores them
x_client = X(handle="your_handle")
Basic Usage
from lukhed_x import X
x_client = X(handle="your_handle")
# Create a post
result = x_client.create_post("Hello, world!")
if not result["error"]:
print(f"Posted: {result['url']}")
print(f"Post ID: {result['postID']}")
# Post with an image
upload = x_client.upload_media("path/to/image.jpg")
x_client.create_post("Check out this image!", media_ids=[upload["mediaID"]])
# Reply
x_client.create_post(".@username Thanks for the great post!", reply_to_post_id="1234567890")
# Poll
x_client.create_post("Who wins?", poll_options=["Ravens", "Steelers"], poll_duration_minutes=1440)
# Read your own timeline (owned read, $0.001)
x_client.get_my_posts(max_results=10)
# Delete
x_client.delete_post("your_post_id")
Available Methods
Posts (write): create_post, delete_post, hide_reply, unhide_reply
Posts (read): get_post, get_posts, get_my_posts, get_user_posts, get_my_mentions,
get_home_timeline, search_recent_posts, get_recent_post_counts, get_quote_posts,
get_reposters, get_liking_users
Engagement: like_post, unlike_post, repost, unrepost, follow_user, unfollow_user,
mute_user, unmute_user
Users: get_me, get_user, get_users, get_my_followers, get_my_following,
get_user_followers, get_user_following, get_my_liked_posts, get_my_muted, get_my_blocked
Lists: create_list, update_list, delete_list, add_list_member, remove_list_member,
get_list, get_list_posts, get_my_lists
DMs: send_dm, get_dm_events
Media: upload_media
Read methods accept any X API v2 field/expansion parameter
as a keyword argument, e.g. get_my_posts(max_results=20, tweet_fields=["public_metrics"]).
X API Setup
- Create a developer account at developer.x.com
- Buy credits at console.x.com and set a spending cap
- Create an app with Read and Write permissions and generate credentials
- You'll need:
- API Key
- API Secret
- Access Token
- Access Token Secret
- Bearer Token (optional, only for app-only endpoints like
get_recent_post_counts)
For detailed instructions, visit the X API Getting Started Guide.
Key Management Options
Authentication is handled by LukhedAuth under the project name xapi, keyed by handle, so one
install can drive multiple bot accounts.
GitHub Storage (Default)
x_client = X(handle="your_handle", key_management="github")
Stores credentials in a private GitHub repository, allowing access across different devices. You will need a github access token: Managing your personal access tokens
Local Storage
x_client = X(handle="your_handle", key_management="local")
Stores credentials in your local file system.
Provide Auth Directly
x_client = X(handle="your_handle", provide_auth={
"apiKey": "...", "apiSecret": "...",
"accessToken": "...", "accessTokenSecret": "..."
})
Error Handling
All methods return a consistent structure:
result = x_client.create_post("Hello!")
if result["error"]:
print("Function Error:", result["errorData"]["functionError"])
print("Tweepy Error:", result["errorData"]["tweepyError"])
else:
print("Success:", result["url"])
Notes and Limitations
- Auth: OAuth 1.0a user context. X still supports it for v2, but their docs now lead with OAuth 2.0, so expect a migration eventually.
- Media upload: uses the v2 chunked flow (
initialize/append/finalize). X documents those endpoints for OAuth 2.0 with themedia.writescope, so OAuth 1.0a may return a 403. - Quote posts:
quote_post_idnow requires an Enterprise plan. - Bookmarks and Spaces: omitted, they need OAuth 2.0 user context.
- Blocking: X removed the v2 write endpoints.
get_my_blockedreads only. - Deprecated but kept:
create_tweet,delete_tweetandget_my_user_infostill work and return the same keys as before.create_tweet(image_data=...)now expects a file path.
Migrating from 0.1.x
X(..., x_api_setup=True)is gone. Setup runs automatically when no keys are found for a handle.- v1.1 methods and the version switching helpers are gone.
- Existing stored keys keep working. Re-run setup only if you want to add a bearer token.
License
This project is licensed under the MIT License.
Support
For issues and questions, please open an issue on the GitHub repository.
Note: This wrapper is designed for legitimate bot usage and follows X's Terms of Service. Please ensure your bot complies with X's automation rules and rate limits.
Metadata
Release files for lukhed-x 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lukhed_x-0.2.0.tar.gz | 12.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lukhed_x-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.3 kB
Release files / lukhed_x-0.2.0.tar.gz
| Download URL | lukhed_x-0.2.0.tar.gz |
|---|---|
| Size | 12.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
da3cf7302675820e6d6f5323be17ae13d7d6d6806c5fe54a4f4d6abc8a517c07
|
|
BLAKE2b-256 checksum How to use checksums |
fec9318c19432643c95ac4c21def0d8d0dd8b46dbb448a50a19b66c9e4c53ac8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.0.1 CPython/3.11.9
|
Release files / lukhed_x-0.2.0-py3-none-any.whl
| Download URL | lukhed_x-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8e239e6ad37e48ed4a64f2ea52d85994d15a38540a8e86737a0dde3cffcbd322
|
|
BLAKE2b-256 checksum How to use checksums |
d493586afed3fc1031e6be96a6b7c7ffc553dd7885ca51d1b1c5b8da9877f398
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.0.1 CPython/3.11.9
|