API keys and network access

What the XT API key must be allowed to do, why the platform forces IPv4, what happens when XT geo-blocks your server, and how to route the provider through a proxy.

5 min readUpdated 3 August 2026api-keys, ipv4, proxy, geo-blocking, security

One XT API key backs the whole platform. Every customer's order, every deposit address, every withdrawal is signed with it. There is no per-user key and no sub-account model here — as far as XT is concerned, your platform is a single trader.

That makes the key's permissions and its network reachability the two settings with the largest blast radius on this product.

The credentials the platform reads

Two variables, named after the provider's name column uppercased:

XT API key. Read at connection time; the connection is then cached for the process lifetime
XT API secret. Missing or blank on either variable and the provider never connects

There is no third credential. XT's ccxt descriptor declares apiKey: true and secret: true, with password: false. The shared loader also reads APP_XT_API_PASSPHRASE — it is the same code path KuCoin uses — but XT discards it, so setting it neither helps nor hurts.

If either variable is empty the manager logs API credentials for xt are missing, increments a failure counter and returns nothing. After three such failures it refuses to attempt a connection again for 30 minutes, regardless of what you fix in between. Restart the backend after correcting the credentials rather than waiting it out.

Permissions to grant on the key

Match the permissions to what you intend to offer. Each of these fails at a different moment, and none of them fails at the moment you create the key.

XT permission Needed for Symptom when absent
Read / account info Everything. fetchBalance is what the Verify button calls Verification fails outright; the provider falls back to a public, unauthenticated instance
Spot trading createOrder, fetchOrder Customers can browse and see live prices; every order returns "Unable to process order"
Deposit address fetchDepositAddress / fetchDepositAddresses The deposit screen cannot produce an address for any network
Deposit and withdrawal history fetchDeposits, fetchWithdrawals Deposits are never credited; withdrawal status never resolves past its initial state
Withdraw exchange.withdraw Withdrawals fail at submission with a generic message and the customer's balance is restored

Anyone who reads APP_XT_API_SECRET off your server can move funds out of your XT account, subject only to XT's own address whitelist. If you can operate without programmatic withdrawals — processing them manually instead — do not grant that permission. If you do grant it, XT's withdrawal address whitelist is the control that limits the damage; the platform has no equivalent.

IP whitelisting, and why the platform forces IPv4

XT's API-key IP whitelist accepts IPv4 addresses. The platform therefore pins all exchange traffic to IPv4 at the HTTPS agent, with XT named in the comment:

// Force IPv4 for exchanges like XT.com that don't support IPv6 whitelisting
const httpsAgentIPv4 = new Agent({ family: 4, keepAlive: true, timeout: 30000 });

Without that, a dual-stack server can present an IPv6 source address that is not on the whitelist, and the key is rejected for reasons that look exactly like a bad secret.

Two consequences follow:

  • Whitelist the server's IPv4 address, and confirm it is the address XT actually sees. curl -4 https://api.ipify.org from the app server settles it; a NAT gateway or egress proxy in front of the box can change the answer.
  • A configured proxy replaces the IPv4 agent entirely. When a proxy URL is set on the provider row, the manager builds a proxy agent instead of httpsAgentIPv4. The family: 4 override is gone, so whitelist the proxy's address — and use an IPv4-capable proxy.

Changing the server's address — a migration, a new load balancer, a floating IP reassignment — breaks the key silently. Re-whitelist before you cut over.

Geo-blocking

XT restricts access from a number of jurisdictions. The list the admin panel shows for this provider is:

United States, Canada, Mainland China, Cuba, North Korea, Singapore, Sudan, Syria, Venezuela, Indonesia, Crimea

This is about the server's location, not your customers'. A VPS in a restricted region gets HTTP 451 on every call, and the platform recognises that specific case:

Access denied: Your server's location is blocked by this exchange. Please
configure a proxy in the Settings tab to connect through an allowed region.

The cleanest fix is to host the backend where XT accepts connections. Where that is not possible, the provider supports a proxy.

Routing XT through a proxy

The proxy is configured per provider row, not in .env, and it is stored in the proxyUrl column on the exchange table. Admin → Finance → Exchange → Settings tab.

Supported schemes are http://, https://, socks4:// and socks5://, with optional credentials in the URL:

http://user:pass@proxy.example.com:8080
socks5://proxy.example.com:1080
  1. Paste the proxy URL into the Proxy URL field. Do not save yet.

  2. Press Test Proxy. The test builds a separate, credential-less XT instance through the proxy agent and calls fetchTime(). It does not touch the running connection, so a failed test costs your live site nothing.

  3. Read the result. The test distinguishes the cases that matter:

    • Proxy connected but the proxy server's location is also blocked — the proxy is in a restricted region too. Pick another region.
    • Failed to connect to proxy serverECONNREFUSED, ETIMEDOUT or ENOTFOUND. The proxy is wrong or down.
    • Proxy authentication failed — HTTP 407, wrong credentials in the URL.
  4. Save only after a successful test. Saving clears the settings cache and evicts the cached XT instance, so the next call rebuilds the connection through the new proxy without a restart.

Two things the proxy form will not tell you:

  • The proxy must support HTTPS CONNECT. XT's API is HTTPS-only (https://sapi.xt.com for spot), and so is its WebSocket transport (wss://stream.xt.com). A plain HTTP forward proxy that cannot tunnel will fail every call.
  • Credentials in the URL are stored in the database. They are masked when the row is read back over the admin API, but the stored value is plaintext. Treat the proxy password as a secret of the same class as the API secret.

Rotating the key

Rotation is a restart, not a hot swap. The exchange instance is cached in memory with the credentials it was built from, and nothing invalidates that cache when .env changes.

  1. Create the new key on XT with the same permissions, and whitelist the server or proxy address on it.
  2. Update APP_XT_API_KEY and APP_XT_API_SECRET in .env.
  3. Restart the backend — pnpm stop && pnpm start.
  4. Press Verify Credentials and confirm a valid result.
  5. Only then delete the old key on XT.

Deleting the old key before the restart lands means every spot call fails in the window between the two, including in-flight withdrawals.

What is never exposed

The API key and secret never leave the server. The admin provider page displays only the names of the variables it expects — APP_XT_API_KEY, APP_XT_API_SECRET — so an operator can check spelling without the value being sent to a browser. Nothing in the admin API returns the credential values, and the proxy URL is masked before it is returned.