USDT Invoice documentation. Self-hosted USDT and TRX payments, 0% fees, one-time price.

USDT Invoice

Self-hosted crypto payment gateway for USDT (TRC20) and TRX. Customers pay straight into your wallet. No middleman, no fees, and no private key ever touches your server.

What you get
  • Merchant dashboard: invoices, on-chain payments, API keys, settings.
  • Hosted payment page with QR code that updates itself and returns the customer to your store.
  • Two wallet modes: Simple (one address) and Advanced (a fresh address per invoice from your xpub).
  • REST API + signed webhooks (HMAC-SHA256) with automatic retries.
  • Ready-made WooCommerce payment method (works with the new block checkout).
  • Live pricing: USD, EUR, GBP and 150+ fiat currencies.

How it works

  1. Your store (or the dashboard) creates an invoice: an amount in fiat, converted to USDT or TRX at the live rate.
  2. The customer opens the payment page, scans the QR with any TRON wallet (Trust Wallet, TronLink, Binance withdrawal, etc.) and sends the exact amount.
  3. USDT Invoice watches the blockchain for that address and amount. As soon as the transfer appears the page shows paid, and once it has the required confirmations it becomes confirmed.
  4. Your store receives a signed webhook and marks the order as paid. The customer is sent back to your thank-you page.
The server only stores public information: an address (Simple mode) or an extended public key (Advanced mode). It can watch for incoming funds; it can never spend them.

Requirements

ItemRequirement
PHP8.0 or newer
DatabaseMySQL 5.7+ / MariaDB 10.3+ (PDO MySQL extension)
PHP extensionscurl, json, pdo_mysql, bcmath or gmp, sodium (all standard on cPanel hosts). gmp is required only for Advanced (xpub) mode.
HTTPSStrongly recommended (a free Let's Encrypt certificate is fine).
CronAbility to run a cron job every 5 minutes, or an external cron service (free ones exist).
TronGrid keyFree at trongrid.io. Optional but recommended (higher rate limits).

The installer checks all of this for you before it starts.

Installation

1. Create a database

In cPanel (or your host's panel) create a MySQL database and a user with all privileges on it. Keep the name, user and password handy.

2. Upload the files

Upload the contents of the usdtinvoice/ folder from the package to the location you want, e.g. public_html/pay/ (so the gateway lives at https://yourdomain.com/pay/) or to a sub-domain such as pay.yourdomain.com.

3. Enter the database details

Open inc/db.php and fill in the four database lines near the top. This is the only file you ever edit by hand.

define('CG_DB_HOST', 'localhost');
define('CG_DB_NAME', 'your_db_name');
define('CG_DB_USER', 'your_db_user');
define('CG_DB_PASS', 'your_db_password');

4. Run the installer

  1. Open https://yourdomain.com/pay/install.php in your browser.
  2. Ownership check. The installer writes a file inc/install.key. Open it in your file manager, copy the key and paste it into the installer. This proves you own the server, so nobody else can run the installer on your site.
  3. Requirements. All rows must be green.
  4. Purchase code. Paste the purchase code from your order. It is bound to this domain (see License & domains).
  5. Admin account. Choose a username and a password (8+ characters).
  6. Where payments go. Pick Simple and paste your TRON address (starts with T), or Advanced and paste your xpub. You can change this later in Settings.
  7. Click Install USDT Invoice. The installer creates the tables, then locks itself (it renames to install.php.locked, which you may delete).
Wrong wallet address = lost money. Copy it from your wallet app, never type it. The installer and the Settings page verify the address checksum, but they cannot know whether it is your wallet.

5. Set up the cron job

See the next section. Without the cron, payments are still detected while a customer has the payment page open, but webhooks, expiry and retries need the scanner.

Payment scanner (cron)

The scanner runs every 5 minutes: it expires old invoices, checks the blockchain for open ones, matches transfers, and delivers webhooks (with retries). Set it up in one of two ways.

Option A - server cron (cPanel → Cron Jobs)

*/5 * * * * /usr/local/bin/php /home/USER/public_html/pay/cron/scan.php >/dev/null 2>&1

The exact PHP path and folder are shown on the dashboard's Settings → Payment scanner card - copy them from there.

Option B - URL cron (any external cron service)

https://yourdomain.com/pay/cron/scan.php?key=YOUR_CRON_SECRET

The secret is shown in Settings. Use Rotate secret if it ever leaks. The top bar of the dashboard shows Scanner active (green) when the cron is running normally, idle (amber) after 3 minutes without a run and stopped (red) after 15.

Receiving wallet modes

SimpleAdvanced (xpub)
What you enterOne TRON addressExtended public key (xpub)
How invoices are told apartEach open invoice gets a slightly different amount (e.g. 25.0031 USDT)Each invoice gets its own fresh address; amount is exact
Best forMost merchants, fastest setupHigh volume, or when customers must pay round amounts
NeedsNothing extraPHP gmp extension + a wallet that exports an xpub

Getting your xpub

Export the account-level extended public key for TRON (derivation path m/44'/195'/0') from your wallet or from a tool that supports it. Paste it in Settings. USDT Invoice immediately shows "First address derived from this key (#0)" - it must match the first receiving address in your wallet. If it does not, you pasted the wrong key.

An xpub can only generate addresses. Even if your server were fully compromised, nobody could move your funds.

Merchant dashboard

Sign in at https://yourdomain.com/pay/admin/.

Every destructive action (cancel, delete, accept underpaid) asks for confirmation in a dialog that matches the dashboard - no browser pop-ups.

Invoices & statuses

StatusMeaningWhat you should do
pendingWaiting for paymentNothing
paidTransfer seen on chain, waiting for confirmationsPut the order on hold
confirmedFinal - funds are in your walletDeliver the order
underpaidCustomer sent less than required (beyond the tolerance)Ask the customer to send the rest, or accept it from the dashboard
expiredLifetime passed with nothing receivedCancel the order
cancelledCancelled from the dashboard-

A payment that arrives after an invoice expired is still matched (the scanner looks 15 minutes before creation and until expiry); the invoice moves to paid/confirmed as usual.

Settings reference

SettingDefaultNotes
Invoice lifetime30 min5-1440. The payment page shows a countdown.
Confirmations required11 is safe on TRON for most stores; raise it for high-value goods.
Underpayment tolerance0.02 (2%)Covers wallet rounding. An invoice paid within tolerance is treated as fully paid.
Default currencyUSDTUSDT (TRC20) or TRX. Can be overridden per invoice.
Fiat currencyUSDAny 3-letter code (EUR, GBP, AED, ...). Rates refresh every 10 minutes.
Brand nameUSDT InvoiceShown on the payment page and dashboard.
TronGrid API key-Free. Raises the blockchain query limit a lot.

Forgot password

There is deliberately no email reset. On the sign-in page click Forgot your password?, create the file inc/reset.key on your server with the one-time code shown, then set a new password. Only someone with access to the server files can do this; the file is deleted automatically afterwards.

WooCommerce plugin

Install

  1. In WordPress go to Plugins → Add New → Upload Plugin and upload usdtinvoice-woocommerce.zip from the package (or copy the usdtinvoice-woocommerce folder to wp-content/plugins/).
  2. Click Activate.
  3. In USDT Invoice's dashboard open API keys, create a key named e.g. "My store", and copy the API key, the API secret (shown once) and the Webhook signing secret.
  4. In WordPress go to WooCommerce → Settings → Payments → USDT Invoice, tick Enable, paste the gateway URL (e.g. https://yourdomain.com/pay, no trailing slash) and the three values, choose USDT or TRX, and Save.

What it does

Tick Debug log to write every request and webhook to WooCommerce → Status → Logs (source: usdtinvoice) while you test.

Free WordPress plugin

A free, limited version is published on WordPress.org as USDT Invoice - Crypto Payments for USDT. It lets a WooCommerce store accept USDT (TRC20) without buying the full script, so you can try the checkout on your own store first.

Free plugin (WordPress.org)

USDT only. No merchant dashboard and no API. Installs from your WordPress admin like any other plugin.

https://wordpress.org/plugins/khaled-hisham-crypto-payments-usdt/ Open the plugin page
Full USDT Invoice

USDT and TRX, merchant dashboard, REST API, signed webhooks, xpub mode and the WooCommerce plugin described above. One-time price, full source code.

https://usdtinvoice.org/buy/ Buy direct, 89 USDT

Install the free plugin

  1. In WordPress go to Plugins → Add New and search for USDT Invoice, or download the zip from the plugin page above and use Upload Plugin.
  2. Click Install Now, then Activate.
  3. Follow the plugin's own settings screen to add your TRON receiving address.

The free plugin and the full script's WooCommerce plugin are separate. When you move to the full version, deactivate the free plugin before activating usdtinvoice-woocommerce so checkout shows one crypto payment method.

API reference

Base URL: your USDT Invoice location, e.g. https://yourdomain.com/pay. All responses are JSON.

Authentication

Send your key and secret as headers on private endpoints:

X-CG-Key:    cg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-CG-Secret: your_api_secret

Rate limits: 60 requests/minute per key on create_invoice, 120 requests/minute per IP on invoice_status.

POST /api/create_invoice.php

FieldTypeRequiredDescription
amountstring/numberyesAmount in fiat, up to 2 decimals, e.g. "49.99"
fiat_currencystringno3-letter code. Default: your setting (USD).
currencystringnoUSDT or TRX. Default: your setting.
order_idstringnoYour reference, shown on the payment page and returned in webhooks.
customer_emailstringnoStored with the invoice.
redirect_urlstringnoWhere to send the customer after payment.
callback_urlstringnoYour webhook endpoint (HTTPS recommended).
metaobjectnoAnything you want back in the webhook (e.g. your internal order id).

Response 200:

{
  "ok": true,
  "invoice": {
    "id": "inv_8db57e14a74d65a960e6",
    "order_id": "1042",
    "status": "pending",
    "currency": "USDT",
    "network": "TRC20",
    "amount": "49.9931",
    "amount_paid": "0",
    "amount_fiat": "49.99",
    "fiat_currency": "USD",
    "address": "TXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "confirmations": 0,
    "expires_at": "2026-09-11T12:39:00Z",
    "paid_at": null,
    "created_at": "2026-09-11T12:09:00Z",
    "checkout_url": "https://yourdomain.com/pay/checkout.php?id=inv_8db57e14a74d65a960e6",
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

Send the customer to checkout_url. Errors return {"ok": false, "error": "..."} with HTTP 400/401/429.

GET /api/invoice_status.php?id=inv_...

Public (no auth): the invoice id is a 20-character random token that only the customer holds. Returns the same invoice object. The payment page polls this every 8 seconds; you can too.

Webhooks

When an invoice changes status USDT Invoice POSTs a JSON body to your callback_url. The body is the invoice object plus:

{ ..., "event": "confirmed", "sent_at": "2026-09-11T12:15:02+00:00", "meta": { "wc_order_id": 14 } }
HeaderValue
X-USDTInvoice-Eventpaid, confirmed, underpaid, expired or cancelled
X-USDTInvoice-SignatureHMAC-SHA256 (hex) of the raw request body with your webhook signing secret

Reply with any 2xx status. Anything else is retried after 1 min, 5 min, 15 min, 1 h, 6 h and 24 h. Webhooks are delivered instantly when the customer's payment page detects the change, and by the cron otherwise.

Always verify the signature and only deliver on confirmed. Never trust a "paid" URL parameter or the redirect alone - those can be faked, the signed webhook cannot.

Code examples

Create an invoice (PHP)

$payload = [
  'amount'        => '49.99',
  'fiat_currency' => 'USD',
  'currency'      => 'USDT',
  'order_id'      => '1042',
  'redirect_url'  => 'https://yourstore.com/thank-you',
  'callback_url'  => 'https://yourstore.com/usdtinvoice-webhook.php',
  'meta'          => ['internal_id' => 555],
];
$ch = curl_init('https://yourdomain.com/pay/api/create_invoice.php');
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => json_encode($payload),
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Content-Type: application/json',
    'X-CG-Key: cg_xxxxxxxx',
    'X-CG-Secret: your_secret',
  ],
]);
$res = json_decode(curl_exec($ch), true);
if (!empty($res['ok'])) {
  header('Location: ' . $res['invoice']['checkout_url']);
  exit;
}

Receive a webhook (PHP)

$secret = 'your_webhook_signing_secret';
$body   = file_get_contents('php://input');
$sig    = $_SERVER['HTTP_X_USDTINVOICE_SIGNATURE'] ?? '';

if (!hash_equals(hash_hmac('sha256', $body, $secret), $sig)) {
  http_response_code(401);
  exit('bad signature');
}
$inv = json_decode($body, true);
if ($inv['event'] === 'confirmed') {
  // mark order $inv['order_id'] as paid - $inv['amount_paid'] $inv['currency'] received
}
http_response_code(200);

Create an invoice (cURL)

curl -X POST https://yourdomain.com/pay/api/create_invoice.php \
  -H "Content-Type: application/json" \
  -H "X-CG-Key: cg_xxxxxxxx" -H "X-CG-Secret: your_secret" \
  -d '{"amount":"49.99","currency":"USDT","order_id":"1042"}'

License & domains

Security notes

FAQ & troubleshooting

The dashboard shows "Scanner stopped"

The cron job is not running. Re-check the command in cPanel → Cron Jobs (copy it from Settings) or use the URL cron with an external service.

The customer paid but the invoice is still pending

Open the invoice and click Check blockchain now. If the amount differs from what was requested (Simple mode) the transfer cannot be matched automatically; check Payments for an unmatched transfer and use Accept underpaid if appropriate. Adding a TronGrid key also makes detection more reliable.

"Exchange rate unavailable"

The rate providers could not be reached. Check that the server can make outgoing HTTPS requests (some hosts block them - ask support to allow api.coingecko.com and open.er-api.com).

WooCommerce shows no payment methods

Make sure the gateway is enabled and that URL, key and secret are filled in; the method hides itself when they are empty. Enable Debug log and look at WooCommerce → Status → Logs.

"Advanced mode needs the gmp extension"

Enable gmp in cPanel → Select PHP Version → Extensions, or use Simple mode.

Is there a free version?

Yes. The free WordPress plugin on WordPress.org accepts USDT on WooCommerce stores. It has no dashboard, no API and no TRX; those come with the full script.

I lost my API secret

Secrets are shown once. Create a new key from API keys and disable the old one.

Changelog

1.0.0 - Initial release.

Updates & support

Where you get updates and help depends on where you bought your copy.

Bought on Codester

For updates, support and new versions, visit the official product page on Codester:

https://www.codester.com/items/70692/usdt-invoice-usdt-trc20-trx-payment-gateway?ref=usdtinvoice Open the Codester item page
Bought at usdtinvoice.org

Your purchase code and download link are in your order email. For help or a domain change, write to support with your purchase code.

support@usdtinvoice.org Email support

Thank you for choosing USDT Invoice. Available on Codester and at usdtinvoice.org. Free version on WordPress.org.