Troubleshooting

Symptom-first diagnosis for the XT provider — credentials that verify but do not work, deposits that never credit, the ban switch that silences everything while reporting green, and orders that fill on XT but not in the platform.

6 min readUpdated 3 August 2026troubleshooting, diagnostics, xt, spot

Start at Admin → Finance → Exchange and press Verify Credentials. It is the only check in the product that exercises the full authenticated path — clock sync, loadMarkets(), then fetchBalance() — and its failure messages are specific enough to be diagnostic on their own.

If that passes and things are still wrong, the answer is almost always one of the two failure modes that report green: the public-instance fallback, or the ban switch. Both are covered below.

Fast triage

Symptom Most likely cause
Admin → Finance → Exchange says No active exchange provider No exchange row has status = true
Toggling XT on returns 403 with licenseRequired lic/54510301.lic is missing — activate the licence
API credentials are missing from environment variables .env not set, or the backend has not restarted since it was
Invalid API credentials on a key you know is right The server's source IP is not on XT's whitelist, or it presented IPv6
Access denied: Your server's location is blocked HTTP 451 — XT geo-blocks the server. Configure a proxy
Charts and tickers fine, but no deposit addresses and no balances The connection fell back to a public, unauthenticated instance
Everything is quiet — no prices, no fills, no deposits — and nothing errors The ban switch is set in Redis
Orders fill on XT but never update in the platform processPendingSpotOrders has stopped
A deposit arrived on-chain and was never credited The network name is unmapped for verification
Withdrawal marked COMPLETED but XT still shows it pending The optimistic default when fetchWithdrawals cannot find it
A market cannot be enabled despite full exchange permissions The status endpoint needs edit.ecosystem.market
Portfolio values frozen processCurrenciesPrices has stopped, or the provider is inactive
Every spot endpoint answers 503 No active provider, or startExchange() is returning null
Trade page crashes on a specific market A non-numeric field reached the browser — check the ticker stream for that symbol

Diagnosis in detail

This is the public-instance fallback, and it is the single most misleading state this product can be in.

When loadMarkets() fails for a reason that is neither a rate limit nor a timestamp error, the manager does not stop. It closes the authenticated instance, builds an unauthenticated one, loads markets on it, and caches that. Public data — tickers, candles, order book, market list — keeps flowing. Everything authenticated silently returns nothing.

The signature in the backend log is exact:

Falling back to an unauthenticated xt instance — authenticated data
(deposit/withdraw networks, balances) will be unavailable until valid
API credentials are configured.

Symptoms: deposit screens show no networks for any asset, the exchange balance page is empty, withdrawals fail, and the currency import writes far fewer rows than you expect. The front page looks perfect.

Fix the underlying credential or network problem, then restart the backend — the fallback instance is cached and nothing evicts it.

The ban switch. When XT rate-limits the platform, the unblock time is written to the Redis key exchange:ban_status. While that key is set, ExchangeManager.startExchange() returns null before doing anything, so every spot path — prices, order reconciliation, deposit verification, withdrawals, HTTP routes — returns without acting. No route 500s. No admin screen shows it.

The only signal is a warning in the backend log:

Exchange is banned for 41 minutes and 12 seconds more

The key carries a TTL and self-clears; the ban is clamped to a maximum of 24 hours no matter what XT's error text claims, because that value is scraped out of free-form text and a stray digit run would otherwise take the platform down for years.

To clear it early, delete the key — but only once XT has actually stopped throttling, or you will simply be re-banned:

redis-cli DEL exchange:ban_status

The usual cause is a chart build with too small a request delay. Raise the delay at Admin → Finance → Exchange → Chart before rebuilding large ranges.

Almost always the source address rather than the key.

# What XT actually sees, over IPv4
curl -4 https://api.ipify.org

Compare that with the whitelist on the XT key. Three things commonly break it:

  • A NAT gateway or egress proxy in front of the server, so the address is not the one you see on the box.
  • A proxy configured on the provider row. A proxy replaces the platform's forced-IPv4 agent entirely, so the address to whitelist is the proxy's — and it must be reachable over IPv4.
  • A server migration or floating-IP reassignment since the key was created.

XT's key whitelist does not accept IPv6, which is why the platform pins exchange traffic to family: 4 and names XT in the comment. If you have overridden that with a proxy, you have also given up that protection.

Check the network name first. Deposit verification maps the platform's chain name to XT's long-form network name — TRC20 becomes Tron, ERC20 becomes Ethereum, BEP20 becomes BNB Smart Chain — and returns null for any chain not in its table. On null, the deposit query goes to XT without a chain filter, and the match can fail.

The table covers Tron, Ethereum, BNB Smart Chain, Polygon, Arbitrum, Optimism, Avalanche C-Chain, Solana, Bitcoin, Litecoin, Dogecoin, Base, Ethereum Classic and Bitcoin Cash, under several aliases each. Anything else is unmapped.

The coins are not lost — they are in your XT account. Confirm the deposit in XT's own interface, then credit the wallet manually through the admin wallet tools.

Also check the fee: if XT's network fee is greater than or equal to the deposit, the platform deliberately credits nothing and tells the customer the deposit does not cover the fee.

After calling withdraw, the platform re-reads the withdrawal from fetchWithdrawals to pick up the true fee and status. If it cannot find the row, it records the expected fee and marks the withdrawal COMPLETED.

That default is optimistic. A withdrawal XT has not yet exposed over the API, or one still under review, can be marked complete in the platform. A subsequent failure on XT's side is not reflected back.

Reconcile spot withdrawals against XT's own withdrawal history rather than trusting the platform status. If you process meaningful volume, do it on a schedule.

processPendingSpotOrders runs every 60 seconds and is the only thing that settles an open order. Check Admin → System → Cron for its last run and last error.

If it is running but doing nothing, the provider is the problem, not the job — it returns immediately when there is no active provider or the ban switch is set.

While an order is unsettled the customer's funds stay held in inOrder, so this is a support-visible failure within minutes.

They will not, and that is correct. For a BUY, XT reports info.executedQty as the amount spent, not the amount bought. The platform divides it by info.avgPrice before crediting the wallet.

Your platform records the base amount the customer received. XT's export records the quote amount they spent. Multiply by the average price to compare them.

XT returns some ticker fields as raw strings — notably 24-hour base volume, which arrives in info.q rather than baseVolume. The ticker stream coerces every numeric field to a number for XT specifically, because a string reaching the browser makes .toFixed() throw and takes the whole page with it.

If you see this on a single symbol, capture the raw ticker payload for it: a field the coercion does not cover is the likely cause, and it belongs in a support report.

They are wrong. SPOT wallet rows recorded while a different exchange held the coins are claims against an XT account that never received them. Currencies, markets, symbols, precisions and network names all differ between providers.

There is no migration path in the product. Switching provider on an install with customer balances requires settling those balances first.

Networks are never stored in the database. The deposit and withdrawal screens call XT live on every load, and that call is authenticated. An empty list means the authenticated path is broken — the public-instance fallback, a key without deposit-address permission, or an active ban.

The endpoints that enable and disable a market are gated on edit.ecosystem.market, not edit.exchange.market, despite living under /api/admin/finance/exchange/market. Grant it to the role. It is required whether or not you run the Ecosystem addon.

Log lines worth grepping for

All of these come from the EXCHANGE module in the backend log.

Line Means
API credentials for xt are missing. .env is empty or unread; three of these locks retries for 30 minutes
API credentials for xt are invalid. XT rejected the key; the connection is being rebuilt without credentials
Falling back to an unauthenticated xt instance The public-instance fallback is active
Exchange is banned for … more The ban switch is set
Significant time offset with server: …ms Clock drift over 5 seconds — fix NTP on the server
Timestamp error for xt, recreating exchange with fresh time sync Expected and self-healing; only worrying if it repeats constantly
Using proxy for xt A proxy is configured on the provider row
Failed to load markets: … The reason the fallback is about to happen

What to include in a support report

  • The exact message from Verify Credentials.
  • Whether a proxy is configured, and the result of Test Proxy.
  • The backend log around the failure, including any of the lines above.
  • Whether exchange:ban_status is set: redis-cli TTL exchange:ban_status.
  • The provider row state — active, licensed, version — from Admin → Finance → Exchange.
  • For a money problem: the currency, the network as the customer saw it, the transaction id, and what XT's own interface shows for it.