# Binance Futures testnet API key: two hosts, one demo market

URL: https://fincodelabs.com/en/blog/binance-futures-testnet-api-key · Publisher: Fincode (Fincode Yazılım ve Teknoloji A.Ş.), Istanbul, Turkey · Category: Exchange APIs · Published: 2026-11-06 · Updated: 2026-11-06

Binance Futures testnet API key as of 5 November 2026: creating it on demo.binance.com, demo-fapi vs the old host, the SDK, and tested Python code.

**Short answer:** A **Binance Futures testnet API key** is created on Binance's Futures Demo Trading site: log in at demo.binance.com, open API Management and create a key. Binance's USD-M General Info page gives `https://demo-fapi.binance.com` as the testnet REST URL, while other official pages and the Python SDK's testnet example still name `testnet.binancefuture.com`; on 5 November 2026 both hosts served the same market.

Binance's own pages disagree about which futures test host is current. This guide compares them as read on 5 November 2026, tests both hosts that evening (19:02 to 20:07 UTC) and gives a Python client for signed USD-M orders. No key was created: signed calls went to a local mock, plus placeholder-key calls that both test hosts rejected.

This is a technical guide, not a recommendation of Binance, futures or any setting. Futures are leveraged, and a small price move can liquidate a position. Availability depends on your jurisdiction and Binance's terms. Article 99/A of Capital Markets Law No. 6362 treats activity by foreign crypto-asset platforms directed at Turkish residents as unauthorized, and Article 14 of Capital Markets Board (SPK) Communiqué III-35/B.2 bars leverage and derivatives on crypto assets listed on Turkish platforms, so nothing here describes a route for readers in Turkey.

## How to get a Binance Futures testnet API key

You create it on the Futures Demo Trading site, not a separate testnet website. Binance's testing FAQ (updated 6 October 2025) gives these steps; the derivatives Quick Start (last modified 30 October 2026) points to the same site:

1. Log in to Futures Demo Trading at `demo.binance.com/en/futures`, or use Create if you have no demo account.
2. Open API Management from the account icon, or go to `demo.binance.com/en/my/settings/api-management`.
3. Click Create API and name the key.

- **Key type.** USD-M General Info covers HMAC SHA256 and RSA keys; the USD-M WebSocket API page allows only Ed25519 keys for session login.
- **The old website.** `https://testnet.binancefuture.com/` redirected (HTTP 301) to `demo.binance.com/en/futures/BTCUSDT` on 5 November 2026, so older tutorials are out of date; its API still answered.

The Spot Testnet is separate; see the [Binance API Python guide](https://fincodelabs.com/en/blog/binance-api-python-trading-bot).

## Binance futures testnet URL: what the official pages say

USD-M General Info names `demo-fapi.binance.com`; the user data stream, order and WebSocket API pages and the SDK's TESTNET constants still name `testnet.binancefuture.com`.

**USD-M test hosts named by official sources, read 5 November 2026**

| Source | Date shown | REST | WebSocket |
| --- | --- | --- | --- |
| USD-M General Info | Last modified 30 October 2026 | `https://demo-fapi.binance.com`, where most endpoints work | `wss://demo-fstream.binance.com` |
| User Data Streams and New Order pages | None seen | `https://testnet.binancefuture.com` | Not given |
| USD-M WebSocket API General Info | Last modified 30 October 2026 | Not given | `wss://testnet.binancefuture.com/ws-fapi/v1` (WebSocket API) |
| Market Streams page | None seen | Not given | `wss://stream.binancefuture.com` |
| `binance-common` 4.8.0, the SDK's constants | Published 29 October 2026 | TESTNET: `testnet.binancefuture.com`; DEMO: `demo-fapi.binance.com` | `wss://fstream.binancefuture.com`; no demo constant |

Both dated pages show 30 October 2026, so dates do not settle which text is newer. No page says the older host is retired or which endpoints the demo host lacks. Every listed host answered on 5 November 2026. Keep the host in one configuration value.

## Are demo-fapi and testnet.binancefuture.com the same market?

In tests on 5 November 2026 they behaved as one market: the same trades, symbols and filters, and one rate-limit counter.

Public endpoints only (Python 3.11, `requests`):

```python
import requests

DEMO, OLD, LIVE = ("https://demo-fapi.binance.com", "https://testnet.binancefuture.com",
                   "https://fapi.binance.com")
http = requests.Session()

def get(base, path, **params):
    r = http.get(base + path, params=params, timeout=10)
    r.raise_for_status()
    return r.json(), r.headers.get("X-MBX-USED-WEIGHT-1M")

def one(items, key, value):
    found = [x for x in items if x[key] == value]
    if len(found) == 1:
        return found[0]
    raise LookupError(f"{value}: {len(found)} matches")   # never pick the last of several

def btc_filter(base, kind):
    info, _ = get(base, "/fapi/v1/exchangeInfo")
    return one(one(info["symbols"], "symbol", "BTCUSDT")["filters"], "filterType", kind)

last, used_a = get(DEMO, "/fapi/v1/aggTrades", symbol="BTCUSDT", limit=1)
same, used_b = get(OLD, "/fapi/v1/aggTrades", symbol="BTCUSDT", fromId=last[0]["a"], limit=1)
print("same trade on both hosts:", last == same, "| used weight", used_a, "then", used_b)
print("LOT_SIZE step: demo", btc_filter(DEMO, "LOT_SIZE")["stepSize"],
      "production", btc_filter(LIVE, "LOT_SIZE")["stepSize"])
```

Output at 20:00 UTC on 5 November 2026:

```
same trade on both hosts: True | used weight 20 then 40
LOT_SIZE step: demo 0.0001 production 0.001
```

The second count includes the first host's 20. Both hosts listed the same 743 symbols (942 on production) with identical BTCUSDT filters. This is one evening's observation, not a Binance statement.

## Binance futures API in Python: signed orders on the demo host

Signed USD-M calls send the key in the `X-MBX-APIKEY` header with an HMAC SHA256 signature of the query string, per the General Info page.

This client refuses non-test hosts, checks credentials before any network call, rounds to the filters with `Decimal` and separates a refusal from an unknown outcome. Continuing from the first snippet, pass `{k: btc_filter(DEMO, k) for k in ("LOT_SIZE", "PRICE_FILTER", "MIN_NOTIONAL")}` as `filters`.

```python
import hashlib, hmac, os, re, time
from decimal import Decimal, ROUND_DOWN
from urllib.parse import urlencode, urlsplit
import requests

BASE = os.environ.get("FUTURES_BASE", "https://demo-fapi.binance.com")
TEST_HOSTS = {"demo-fapi.binance.com", "testnet.binancefuture.com", "127.0.0.1"}  # last: mock
CLIENT_ID = re.compile(r"^[\.A-Z\:/a-z0-9_-]{1,36}$")    # from the New Order page

class Refused(Exception): pass    # Binance said no: the order was not accepted
class Unknown(Exception): pass    # the order may exist: look it up before any retry

def on_step(value, f, step="stepSize", lo="minQty", hi="maxQty"):
    if isinstance(value, float):
        raise TypeError("pass a str or Decimal, not a float")
    try:
        d = Decimal(value)
        if not d.is_finite():
            raise ValueError(f"not finite: {repr(value)}")
        d = (d / Decimal(f[step])).to_integral_value(ROUND_DOWN) * Decimal(f[step])
    except ArithmeticError:                            # not a number, or overflow
        raise ValueError(f"not a usable number: {repr(value)}") from None
    if not Decimal(f[lo]) <= d <= Decimal(f[hi]):
        raise ValueError(f"{value} rounds outside {f[lo]} to {f[hi]}")
    return format(d.normalize(), "f")

def signed(method, path, **params):
    key, secret = os.environ.get("DEMO_API_KEY"), os.environ.get("DEMO_API_SECRET")
    if not key or not secret:                          # before any network call
        raise SystemExit("set DEMO_API_KEY and DEMO_API_SECRET")
    if urlsplit(BASE).hostname not in TEST_HOSTS:
        raise SystemExit(f"refusing {BASE}: not a test host")
    params.update(timestamp=int(time.time() * 1000), recvWindow=5000)
    query = urlencode(params)
    query += "&signature=" + hmac.new(secret.encode(), query.encode(), hashlib.sha256).hexdigest()
    try:
        r = requests.request(method, f"{BASE}{path}?{query}",
                             headers={"X-MBX-APIKEY": key}, timeout=10)
    except requests.RequestException as err:
        raise Unknown(type(err).__name__) from err
    if r.status_code >= 500 or r.status_code == 408:
        raise Unknown(r.status_code)
    try:
        body = r.json()
    except ValueError:                                 # an HTML page, say
        outcome = Unknown if r.status_code < 400 else Refused   # 2xx: may be accepted
        raise outcome(r.status_code, None, r.text[:30]) from None
    if r.status_code >= 400:
        err = body if isinstance(body, dict) else {}
        if err.get("code") in (-1006, -1007):
            raise Unknown(err["code"])
        raise Refused(r.status_code, err.get("code"), err.get("msg"))
    return body

def limit_order(filters, side, qty, price, cid, test=True):
    if not isinstance(cid, str) or not CLIENT_ID.fullmatch(cid):
        raise ValueError(f"client order id {repr(cid)} does not match the pattern")
    q = on_step(qty, filters["LOT_SIZE"])
    p = on_step(price, filters["PRICE_FILTER"], "tickSize", "minPrice", "maxPrice")
    if Decimal(q) * Decimal(p) < Decimal(filters["MIN_NOTIONAL"]["notional"]):
        raise ValueError("notional below the minimum")
    return signed("POST", "/fapi/v1/order/test" if test else "/fapi/v1/order",
                  symbol="BTCUSDT", side=side, type="LIMIT", timeInForce="GTC",
                  quantity=q, price=p, newClientOrderId=cid)
```

Output at 20:38 UTC on 5 November 2026. Only line two reached Binance (the demo host, malformed key `placeholder`); lines four, five and seven used a local mock that checks signatures and mimics documented answers:

```
no key set: stopped: set DEMO_API_KEY and DEMO_API_SECRET
real demo host, placeholder key: Refused (401, -2014, 'API-key format invalid.')
production host: stopped: refusing https://fapi.binance.com: not a test host
mock, order: {'orderId': 1001, 'clientOrderId': 'demo-1', 'status': 'NEW', 'price': '60000', 'origQty': '0.0023'}
mock, same id again: Refused (400, -4116, 'clientOrderId is duplicated')
qty 1e400: ValueError: 1e400 rounds outside 0.0001 to 1000
mock timeout: Unknown ('ReadTimeout',)
```

- **Duplicates.** A repeated open client order ID gets `-4116`, per the USD-M error page; an empty ID, or one ending in a newline that `re.match` with `$` would pass, never leaves the process.
- **Bad input.** `"1e400"` and `"1e-400"` fail after rounding instead of reaching the wire as a huge number or zero. A float, `nan`, `"1e999999"`, an HTML 403, an error body without `code` and a wrong secret also failed cleanly.
- **Unknown outcomes.** A 503, a 408 (General Info: backend timeout), a 200 with an HTML body, a read timeout, `-1007` and a refused connection raised `Unknown`: look the order up by client ID before sending again.

Both hosts answered `POST /fapi/v1/order/test` with `-2014` and an unknown path with 404; SDK 18.2.0 documents it as a test order not sent to the matching engine. See [Binance API error codes](https://fincodelabs.com/en/blog/binance-api-error-codes).

## Binance futures connector for Python: which package is current

The current official package is `binance-sdk-derivatives-trading-usds-futures`; the older `binance-futures-connector` calls itself deprecated on PyPI.

**Python packages on PyPI, read 5 November 2026**

| Package | Version (uploaded) | Python | Status |
| --- | --- | --- | --- |
| `binance-sdk-derivatives-trading-usds-futures` | 18.2.0 (29 October 2026) | 3.11 to 3.15 | Current |
| `binance-futures-connector` | 4.2.0 (30 April 2026) | 3.7 or later | Deprecated |

Three details in the 18.2.0 README trap a copy-paste: the REST testnet example uses the TESTNET constant, not `DERIVATIVES_TRADING_USDS_FUTURES_REST_API_DEMO_URL`; its Futures Testnet link points to the Spot Testnet, `testnet.binance.vision`; and the streams example imports one constant but passes another, a `NameError`. The SDK was not run; constants come from its wheel files.

## What the Binance futures demo cannot show you

The demo host tests signing and order handling, but its filters, symbols, limits and stream paths differ from production; see also [paper trading API](https://fincodelabs.com/en/blog/paper-trading-api).

**exchangeInfo, 20:00 UTC on 5 November 2026: BTCUSDT filters and weight limit**

| Item | Demo (both hosts) | Production |
| --- | --- | --- |
| LOT_SIZE step and minimum | 0.0001 | 0.001 |
| PRICE_FILTER range (tick 0.10 on both) | 261.10 to 809,484 | 556.80 to 4,529,764 |
| PERCENT_PRICE band | 0.95 to 1.05 | 0.97 to 1.03 |
| MAX_NUM_ORDERS | 10,000 | 200 |
| MIN_NOTIONAL | 50 | 50 |
| REQUEST_WEIGHT per minute | 6,000 | 2,400 |

> **Hypothetical example.** A bot tuned on the demo host sends 0.0015 BTC: valid for the demo step of 0.0001, rejected by production's 0.001. Reading filters at startup avoids this.

- **Stream paths.** The USD-M changelog added `/public`, `/market` and `/private` paths on 5 March 2026 and on 2 April set 23 April 2026 to decommission legacy URLs. At 20:02 UTC on 5 November 2026, production's legacy `wss://fstream.binance.com/ws/btcusdt@markPrice` and `@aggTrade` sent nothing in 20 seconds while `@bookTicker` streamed; markPrice streamed on the demo host's legacy path and production's `/market/ws/` path. See the [Binance WebSocket guide](https://fincodelabs.com/en/blog/binance-websocket-api).

### Historical files for replay tests

A Python check downloaded the daily USD-M BTCUSDT 1h kline file for 4 November 2026 from `data.binance.vision` (Last-Modified 08:03 GMT on 5 November) with its `.CHECKSUM`, compared the SHA-256 and read the CSV without printing prices. Output at 20:01 UTC that day:

```
checksum ok: True
['open_time', 'open'] 24 rows; open_time digits: 13
```

Spot files use microseconds from 1 January 2025, per the README, which gives no unit for futures; this file used milliseconds. The dataset terms, last updated 26 August 2026, allow only non-commercial use under CC BY-NC-SA 4.0 and exclude commercial trading bot platforms. See the [Binance historical data guide](https://fincodelabs.com/en/blog/binance-historical-data-api).

## Binance futures leverage and liquidation risk

Futures multiply gains and losses, and a liquidation can take a position's whole margin.

This guide suggests no leverage, margin mode or strategy. The [liquidation price calculator](https://fincodelabs.com/en/tools/liquidation-price-calculator) shows on hypothetical numbers how leverage moves a liquidation price, and [perpetual futures and funding rate](https://fincodelabs.com/en/blog/perpetual-futures-funding-rate) explains funding.

For integration work in general, see [exchange API integration](https://fincodelabs.com/en/services/exchange-api-integration); naming Binance here does not mean Fincode integrates it or has built on it.

## Frequently asked questions

### Is the Binance futures testnet free?

Binance's testing FAQ (updated 6 October 2025) says you can test your use cases for free. Access depends on your jurisdiction and Binance's terms.

### Does testnet.binancefuture.com still work?

Its REST and WebSocket APIs answered on 5 November 2026, the REST API serving the same market as demo-fapi.binance.com, but its website redirects to demo.binance.com.

### Can I use my Spot Testnet key for futures?

No official page read on 5 November 2026 says so. Binance's FAQ sends futures users to demo.binance.com for keys.

### Why does the futures testnet return -2014 or -2015?

-2014 means a malformed key; both hosts returned it for a placeholder key on 5 November 2026. -2015 means the key, IP or permission was rejected, so check that the key came from the demo site.

## Sources

- [Binance Derivatives: USD-M Futures General Info (testnet base URLs, last modified 30 October 2026)](https://developers.binance.com/docs/derivatives/usds-margined-futures/general-info)
- [Binance Derivatives: Quick Start (Futures Demo Trading page, last modified 30 October 2026)](https://developers.binance.com/docs/derivatives/quick-start)
- [Binance Derivatives: USD-M User Data Streams (testnet.binancefuture.com)](https://developers.binance.com/docs/derivatives/usds-margined-futures/user-data-streams)
- [Binance Derivatives: USD-M New Order (client order ID pattern)](https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api)
- [Binance Derivatives: USD-M WebSocket Market Streams (URL paths)](https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-market-streams)
- [Binance Derivatives: Change log (USD-M WebSocket entries of 5 March and 2 April 2026)](https://developers.binance.com/docs/derivatives/change-log)
- [Binance Derivatives: USD-M error codes (-1007, -2014, -2015, -4116)](https://developers.binance.com/docs/derivatives/usds-margined-futures/error-code)
- [Binance FAQ: How to Test My Functions on Binance Testnet (updated 6 October 2025)](https://www.binance.com/en/support/faq/how-to-test-my-functions-on-binance-testnet-ab78f9a1b8824cf0a106b4229c76496d)
- [Binance Derivatives: USD-M WebSocket API General Info (testnet URL, Ed25519 session login, last modified 30 October 2026)](https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-api-general-info)
- [PyPI: binance-sdk-derivatives-trading-usds-futures (official USD-M SDK)](https://pypi.org/project/binance-sdk-derivatives-trading-usds-futures/)
- [PyPI: binance-futures-connector (deprecated)](https://pypi.org/project/binance-futures-connector/)
- [binance-public-data: README (Spot timestamps in microseconds from 1 January 2025)](https://github.com/binance/binance-public-data/blob/master/README.md)
- [Binance Vision dataset terms (last updated 26 August 2026)](https://github.com/binance/binance-public-data/blob/master/TERMS_AND_CONDITIONS.md)
- [Capital Markets Law No. 6362, consolidated text, Article 99/A (Turkish)](https://www.mevzuat.gov.tr/mevzuatmetin/1.5.6362.pdf)
- [Resmî Gazete: SPK Communiqué III-35/B.2 on crypto-asset service providers, Article 14 (Turkish)](https://www.resmigazete.gov.tr/eskiler/2025/03/20250313-6.htm)

> This guide is general information about software and markets, not investment, legal or tax advice. Automated trading can lose money, past or backtested performance does not guarantee future results, and the rules that apply depend on your jurisdiction and your exchange's terms. Sources, checks and corrections: see the [editorial policy](https://fincodelabs.com/en/editorial-policy).

---

Published by Fincode (Fincode Yazılım ve Teknoloji A.Ş.), a software company in Istanbul, Turkey: https://fincodelabs.com/en/blog/binance-futures-testnet-api-key

Cite as: Fincode, "Binance Futures testnet API key: two hosts, one demo market", updated November 6, 2026, https://fincodelabs.com/en/blog/binance-futures-testnet-api-key
