How to Accept USDT Payments with a Self-Hosted Crypto Payment Gateway
A complete guide to setting up your own self-hosted cryptocurrency payment gateway — accept USDT (ERC-20, TRC-20, BEP-20) and 100+ other tokens with full control over your funds.
Why Accept USDT Payments?
USDT (Tether) is the most widely used stablecoin in the world, with a market cap exceeding $140 billion. For businesses, accepting USDT offers several advantages over traditional payment methods:
- No chargebacks — crypto payments are irreversible once confirmed on-chain
- Global reach — anyone with a crypto wallet can pay you, anywhere in the world
- Low fees — pay only blockchain gas fees, no 2-3% processing fees like credit cards
- Instant settlement — funds arrive in your wallet within minutes, no bank delays
- Multi-chain — accept USDT on Ethereum (ERC-20), Tron (TRC-20), BNB Chain (BEP-20), and more
The Problem with Hosted Payment Gateways
Most crypto payment processors like CoinGate, OpenNode, or NowPayments are hosted solutions — they hold your funds, charge platform fees (typically 0.5-1%), and you're trusting a third party with your private keys.
A self-hosted crypto payment gateway solves this by running on your own infrastructure. Your private keys never leave your server, every payment goes directly to your wallet, and there are zero platform fees.
Option 1: Deploy Xcash (3 Minutes)
Xcash is an open-source, self-hosted cryptocurrency payment gateway that supports 100+ blockchains, including all major USDT networks.
Prerequisites
- A Linux server (1 vCPU, 2GB RAM minimum)
- Docker and Docker Compose installed
- A domain name pointed to your server
- RPC endpoints for your chosen blockchain(s)
Step 1: Clone and Initialize
git clone https://github.com/xca-sh/xcash.git
cd xcash
./scripts/init_env.sh Step 2: Configure Your Domain
SITE_DOMAIN=your-domain.com Step 3: Start the Services
docker compose up -d Step 4: Configure Blockchain RPC
Log in to the admin panel (default: admin / Admin@123456), navigate to Chain Management, and add RPC endpoints for the chains you want to support:
- Ethereum — for ERC-20 USDT
- Tron — for TRC-20 USDT (most popular, lowest fees)
- BNB Chain — for BEP-20 USDT
- Arbitrum / Base / Polygon — for L2 USDT options
Accepting Your First USDT Payment
Create a payment invoice using the REST API:
import hashlib, hmac, json, time, uuid
import requests
API_BASE = "https://your-domain.com/api"
APPID = "your-app-id"
HMAC_KEY = "your-hmac-key"
def create_invoice():
body = json.dumps({
"out_no": "order-20260515-001",
"title": "Premium Plan",
"currency": "USD",
"amount": "29.99"
}, separators=(',', ':'))
timestamp = str(int(time.time()))
nonce = str(uuid.uuid4())
message = nonce + timestamp + body
signature = hmac.new(
HMAC_KEY.encode(), message.encode(), hashlib.sha256
).hexdigest()
resp = requests.post(
f"{API_BASE}/v1/invoice",
data=body,
headers={
"XC-Appid": APPID,
"XC-Timestamp": timestamp,
"XC-Nonce": nonce,
"XC-Signature": signature,
"Content-Type": "application/json"
}
)
return resp.json()
invoice = create_invoice()
print(f"Payment URL: {invoice['pay_url']}")
The pay_url takes your customer to a payment page where they can pay with USDT (or any other supported cryptocurrency).
Option 2: Use Xcash Cloud
Cloud version starting at $49/month. Same features, no infrastructure management.
Security Best Practices
- Use a dedicated server
- Enable IP whitelisting
- Set up withdrawal limits
- Monitor MistTrack risk scores
- Keep secrets safe — back up
.envand HMAC keys
Comparing Self-Hosted Options
| Feature | Xcash | BTCPay Server | CoinGate |
|---|---|---|---|
| Self-Hosted | ✅ | ✅ | ❌ |
| USDT Support | ✅ (ERC-20, TRC-20, BEP-20) | ❌ | ✅ |
| 100+ Chains | ✅ | ❌ Bitcoin only | ✅ |
| Zero Fees | ✅ | ✅ | ❌ 1%+ |
| Deposit/Withdraw | ✅ | ❌ | ❌ |
| Risk Control | ✅ | ❌ | ❌ |
| Deploy Time | 3 minutes | 30+ minutes | N/A |
Conclusion
Accepting USDT payments doesn't have to mean giving up control. A self-hosted payment gateway like Xcash gives you the best of both worlds.
git clone https://github.com/xca-sh/xcash.git
cd xcash && ./scripts/init_env.sh && docker compose up -d Visit xca.sh for the cloud version.