CLI tool
mizorewww/x_gift_bot avatar
mizorewww/x_gift_bot

XGift: self-hosted X Premium gift redemption in Go

X Premium gift CLI and redemption site

1,261 stars391 forksGoMIT

At a glance

What is it?
XGift turns X Premium gifting into a redemption code workflow: a Go service places the order and pays for it, a React admin panel issues codes and tracks batches, and an encrypted vault keeps card numbers and cookies per record. It is a real self-hosted tool with sharp edges around lost password files, expiring X cookies and card rotation on declines.
Who is it for?
Adopt XGift if you already sell X Premium to users and want to issue codes instead of taking each order by hand, and stay away if you only need an occasional gift, because the setup cost includes a real payment card, a Stripe public key and a domain.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

From sending each gift by hand to issuing redemption codes

XGift solves a narrow but annoying problem: selling X Premium as a gift to people who should not have to hand over their own payment details. You generate a redemption code, send it to a buyer, the buyer opens the site and enters the code together with their own X username, and the system places the Premium order and pays for it from the card you configured. The project describes itself in those terms as an X (Twitter) Premium gift redemption platform.

Two surfaces back that up. The redemption page lets the buyer self serve and shows processing progress in real time. The admin backend generates and deactivates codes, groups them into batch folders, shows a statistics panel and tracks order status. The intended operator is a small seller or a community organiser who resells Premium access, not a developer building a social network feature.

The repository is written in Go with a TypeScript and React front end, sits under the MIT licence, and its last push was on 2026-10-09. It has no GitHub releases at all, so the version you get is whatever the default branch holds.

Two Go binaries in front of a React admin panel

The build produces two binaries from two command packages, and the split reflects two different jobs:

code
git clone https://github.com/mizorewww/x_gift_bot.git
cd x_gift_bot
npm ci && npm run build        # 构建前端(只需一次,产物已随仓库提交时可跳过)
go build -tags with_quic,with_utls -o bin/xgift ./cmd/xgift
go build -tags with_quic,with_utls -o bin/xgift-web ./cmd/xgift-web

The first binary is the CLI and the service that runs the redemption flow and the setup wizard. The second serves the web interface. The build tags with_quic and with_utls are what pull in the QUIC and uTLS capabilities from the sing-box dependency tree listed in go.mod, which matters because the proxy layer has to look like ordinary browser traffic to the sites it connects to.

The front end is a separate npm project. Its package.json names the package xgift-web, marks it private, and requires Node 22 or newer, with React 19 and MUI 7 as the main runtime dependencies. The scripts cover a production build, a type check, a preview server and a Lighthouse audit run, so the UI is a real single page application rather than server rendered templates.

A preview mode that never touches real credentials

Before you have any credentials at all, the project gives you a way to look at the interface. The README describes a local preview that runs entirely on sample data in memory and connects to no live service:

code
npm ci
npm run build
npm run preview

The preview server answers on http://127.0.0.1:4173 for the redemption page and http://127.0.0.1:4173/admin for the admin backend. The README also spells out a test payload for the success path: enter XG- followed by 48 letter A characters on the redemption page, which walks the demo through a complete successful flow.

That detail matters more than it looks. The first thing you would otherwise do is paste real card numbers and cookies into a form to see whether it works. The preview removes that step, so you can check the screens and the code format first, and only then move to real credentials.

The frontend build output is committed to the repository, so the npm step is optional in the README's own words. That is convenient, but it also means the shipped assets in the repository and the ones you build yourself can drift apart, and nothing in the README warns you which version the binaries expect.

The setup wizard asks for four things you should not hand over casually

Running the wizard is the point where the project asks for real assets. The command is short:

code
./bin/xgift setup

The wizard prompts step by step, in Chinese, and asks for four categories of input. First, an X login cookie pair named auth_token and ct0, copied from the browser developer tools after logging in to x.com, which is the credential the system uses to send the gift as your X account. Second, one or more payment cards with number, expiry, CVC and the billing name, billing email and two letter billing country that the issuing bank has on file. Third, optionally a proxy node, because the account login and the eligibility check always connect directly while the regional quote check and payment link creation use a proxy exit so that currency and price stay consistent. Fourth, a Stripe public key beginning with pk_live_, which is stored next to the merchant, product and price in the catalog configuration.

The wizard also creates the remaining files: a randomly generated vault password stored at sqlite/vault-password by default, a site.env with your domain such as https://xp.example.com, and a random admin password shown only once and kept in a file. The README states plainly that if the vault password file is lost, all encrypted data cannot be recovered and the only route is deleting vault.db and running setup again. Backup that file together with the databases, not on its own.

Checkout serialises on a lock and rotates cards across nodes

This is where the project earns its reputation and where it also carries risk. Payment cards are rotated randomly over combinations of card and node. The README specifies that the same combination is used for three consecutive orders, that a declined order ends the current combination immediately, that the declined card enters a 30 minute cooldown while the other cards keep rotating, and that a payment side answer of do_not_try_again blocks that card permanently until it is explicitly released. The commands cards list, cards add, cards remove --last4, cards rotate and cards unblock give you the manual levers over that pool, and the admin page shows only the last four digits of each card.

Two safety rules are worth quoting. The web page and the CLI both take the same checkout.lock, submissions are at least 30 seconds apart, and that interval survives a restart. And when the outcome of a payment is unknown, the system marks it pending verification rather than charging again; the buyer triggers a recheck with the original redemption code and the result is reconciled automatically.

The manual recovery path is the most intricate part of the system. An admin previews orders in review state, confirms them, and the server runs them serially with the same card and node rotation. Each original session allows at most three manual retries, and a stale session only gets archived once the admin confirms the original order was not charged, backed by a matching failed query record and a fresh eligibility and price check. Recovered state lives under admin-recovery keys in the encrypted vault.

Where XGift will hurt you

Several limitations are documented plainly, and they should shape your expectations. The X cookie expires, and refreshing it means copying it out of the browser again or running import-chrome on macOS; the system has no session of its own that survives that.

The dependency on a real card is the sharpest edge. Card rotation on decline exists because issuing banks decline transactions, and it means a failure can move to the next card rather than surface to you. For a low volume reseller this is a reasonable trade, but the README also states that a full site pause only happens when every card is permanently blocked, which means partial outages are visible only through the admin status panel.

The deployment story is deliberately conservative. The service only listens on a loopback address such as 127.0.0.1:8787 and needs Caddy or another reverse proxy for HTTPS, and the shipped Caddyfile template only allows Cloudflare origin IPs by default. The project also expects a Linux server, a domain and Go 1.27 or newer, or a local build with the binaries uploaded afterwards.

Finally, the README does not discuss the terms under which X allows automated gifting, and it publishes no changelog, because there are no releases. The last push was on 2026-10-09, so the code moves, but you have no tagged version to pin.

How it differs from taking payments on your own merchant account

The obvious alternative is to sell Premium through a hosted checkout on your own merchant account and skip the X session entirely, or to gift manually one buyer at a time from the X interface. Both change the shape of the problem rather than solving it with a better implementation.

A hosted checkout keeps the payment on your own merchant, gives the buyer a familiar payment page, and never touches your X login cookie or stores card numbers on a server you run. What you give up is the redemption code flow, the batch statistics and the automated gift placement, and you still have to send the Premium yourself afterwards.

XGift takes the opposite position. It drives the checkout that X itself presents, using your X session and a Stripe public key, and it keeps the buyer interaction inside your own site so that codes, batches and success rates are yours to measure. The price of that position is that card numbers, cookies and proxy nodes all live in a vault.db on your machine, that a lost password file destroys the encrypted records, and that every order is an automated interaction with a platform whose rules on such automation the project never discusses.

For a community organiser handing out a handful of gifts, the manual path is less work. For someone selling codes every week, the batch tooling and the reconciliation logic are the parts that pay for themselves.

Editorial conclusion

Adopt XGift if you already sell X Premium to users and want to issue codes instead of taking each order by hand, and stay away if you only need an occasional gift, because the setup cost includes a real payment card, a Stripe public key and a domain. Before deploying, confirm that your X session cookies and card details are ones you are willing to store in a local encrypted database, verify that the vault password file and both databases are backed up together, and check the deploy/Caddyfile template against your own domain before the first real order.

Frequently asked questions

What does XGift need before it can run?

An X login cookie pair named auth_token and ct0, at least one payment card with matching billing details, a Stripe public key starting with pk_live_, and a domain pointing at a Linux server running Go 1.27 or newer. A proxy node is optional if the server can reach x.com directly.

Can I see the interface before entering real credentials?

Yes. The README describes a local preview on Node.js 22 or newer that serves the redemption page on http://127.0.0.1:4173 and the admin page on http://127.0.0.1:4173/admin with sample data only and no live service connection. Entering XG- followed by 48 letter A characters demonstrates the full success flow.

What happens if I lose the vault password file?

The encrypted data cannot be recovered. The README says the only route is deleting vault.db and running xgift setup again, so the password file has to be backed up together with the databases.

How does XGift handle a declined payment?

Payment cards rotate over card and node combinations, with the same combination used for three consecutive orders. A declined order ends the combination at once, the declined card enters a 30 minute cooldown while other cards keep rotating, and a do_not_try_again answer blocks that card permanently until it is released explicitly.

Does XGift charge a buyer twice if a payment result is unknown?

No. The system marks such an order as pending verification instead of paying again, and the buyer can trigger a recheck with the original redemption code so the result is reconciled automatically. Payments also run under a single checkout.lock with at least 30 seconds between submissions.

How do I pause incoming redemptions?

Set XGIFT_PAYMENTS_ENABLED to false in site.env and restart the service. Buyers are turned away politely and their redemption codes are not consumed, and the manual recovery path in the admin panel stays independent of that switch.

Official sources

  1. Issues
  2. License: MIT
  3. mizorewww/x_gift_bot on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mizorewww-x-gift-bot.svg)](https://hysenlabs.com/projects/mizorewww-x-gift-bot)

Was this useful?